iosswiftuiresponder

How can I put UIResponder prior to Gesturer Recognizer


What I was trying to do is let user select a row and retrieve cell content within it in another text field to edit at the same time by recognize long press rather than single click.

The problem is long press recognizer proceeds prior to table view's delegate handler response to select row. Thus everytime content of selected row comes after long press ends which end up with text field receive content of previously selected row, not the current 'press' row as expected.

How could I make a row selected before long press is recognized upon it?

Here is the code, a list of 3 fruit in a tableview. My expectation is when user press one row long time enough, table view acts as being clicked first and set selectedFruit to the fruit name in pressed row, not after long press ends.

class TableViewController: UITableViewController {

    
    let contentList = ["apple", "blackberry","orange"]
    
    @IBOutlet weak var selectedItem: UILabel!
    
    var selectedFruit:String?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let longPressRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(longPressHandler(_:)))
        longPressRecognizer.numberOfTouchesRequired = 1
        longPressRecognizer.allowableMovement = 10
        longPressRecognizer.minimumPressDuration = 0.5
        
        self.view.addGestureRecognizer(longPressRecognizer)

    }

    // MARK: - Table view data source

    override func numberOfSections(in tableView: UITableView) -> Int {
        // #warning Incomplete implementation, return the number of sections
        return 1
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // #warning Incomplete implementation, return the number of rows
        return contentList.count
    }
    
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "contentItem", for: indexPath)
        
        cell.textLabel?.text = contentList[indexPath.row]
        
        return cell
    }
    
    
    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        selectedFruit = contentList[indexPath.row]
    }
    
    @objc func longPressHandler(_ sender:UILongPressGestureRecognizer) {
        
        selectedItem.text = selectedFruit ?? ""
        
    }
}

fruit list


Solution

  • Read UILongPressGestureRecognizer's location, determine which row is at the location(nearest?), and set the row selected.

    let pressLocation = sender.location(in: tableView)
                
    if let indexPath = tableView.indexPathForRow(at: pressLocation) {
        tableView.selectRow(at: indexPath, animated: false, scrollPosition: .none)
        selectedItem.text = contentList[indexPath.row]
    }