How to add gesture to UITableViewCell?

前端 未结 4 783
有刺的猬
有刺的猬 2021-02-05 14:56

I want to add a tap gesture to every cell in a UITableView that edits the content in it. The two ways to add a gesture are in code or through storyboard. I tried bo

相关标签:
4条回答
  • 2021-02-05 15:15

    You don't need to add gesture recognizer to achieve what you are doing.

    • Use the UITableViewDelegate method tableView:didSelectRowAtIndexPath: to detect which row is tapped (this is what exactly your tapGesture is going to do) and then do your desired processing.
    • If you don't like the gray indication when you select cell, type this in your tableView:didEndDisplayingCell:forRowAtIndexPath: just before returning the cell:
      cell?.selectionStyle = .None
    0 讨论(0)
  • 2021-02-05 15:22

    Adding gesture in awakeFromNib method seems much more easier and works fine.

    class TestCell: UITableViewCell {
    
        override func awakeFromNib() {
            super.awakeFromNib()
    
            let panGesture = UIPanGestureRecognizer(target: self,
                                                action: #selector(gestureAction))
            addGestureRecognizer(panGesture)
        }
    
        @objc func gestureAction() {
            print("gesture action")
        }
    }
    
    0 讨论(0)
  • 2021-02-05 15:22

    The easiest way to do this is to add the gesture in a custom UITableViewCell. An easier alternative to setting up a custom delegate pattern is to inform the view controller of the edits would be to use a handler in the form of a closure that the view controller can provide and which is called when user editing is finished. I'm assuming a textField is used to allow cell editing.

    class CustomTableViewCell: UITableViewCell {
    
        func activateTitleEditing() {
            textField.isEnabled = true
            textField.becomeFirstResponder()
        }
    
        // This will hold the handler closure which the view controller provides
        var resignationHandler: (() -> Void)?
    
        @objc private func tap(_ recognizer: UITapGestureRecognizer) {
            guard recognizer.state == .ended else { return }
            activateTitleEditing()
        }
    
        @IBOutlet weak var textField: UITextField! { didSet {
            textField.delegate = self
            let tap = UITapGestureRecognizer(target: self, action: #selector(tap(_:)))
            addGestureRecognizer(tap)
            textField.isEnabled = false
            }}
    }
    
    extension CustomTableViewCell: UITextFieldDelegate {
        func textFieldDidEndEditing(_ textField: UITextField) {
            resignationHandler?()
        }
    }
    

    And within your custom UITableViewController, pass in the handler to be able to make changes to your model. Don't forget to account for possible memory cycles in the closure.

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        // initialize and return table view cell
        let cell = tableView.dequeueReusableCell(withIdentifier: K.documentCellIdentifier, for: indexPath)
        assert(cell is CustomTableViewCell, "Document cell dequeuing error")
        let customCell = cell as! DocumentTableViewCell
        customCell.textField.text = documentModel.documents[indexPath.row]
        customCell.resignationHandler = { [weak self, unowned customCell] in
            guard let self = self else { return }
            if let newTitle = customCell.textField.text {
                self.cellModel.cells[indexPath.row] = newTitle
            }
        }
        return customCell
    }
    
    0 讨论(0)
  • 2021-02-05 15:24

    To add gesture to UITableViewCell, you can follow the steps below:

    First, add gesture recognizer to UITableView

    tapGesture = UITapGestureRecognizer(target: self, action: #selector(tableViewController.tapEdit(_:)))
    tableView.addGestureRecognizer(tapGesture!)
    tapGesture!.delegate = self
    

    Then, define the selector. Use recognizer.locationInView to locate the cell you tap in tableView. And you can access the data in your dataSource by tapIndexPath, which is the indexPath of the cell the user tapped.

    func tapEdit(recognizer: UITapGestureRecognizer)  {
        if recognizer.state == UIGestureRecognizerState.Ended {
            let tapLocation = recognizer.locationInView(self.tableView)
            if let tapIndexPath = self.tableView.indexPathForRowAtPoint(tapLocation) {
                if let tappedCell = self.tableView.cellForRowAtIndexPath(tapIndexPath) as? MyTableViewCell {
                    //do what you want to cell here
    
                }
            }
        }
    }
    

    It is possible to add gesture directly to TableView cell and access the datasource in viewController, You need to set up a delegate:

    In your custom cell:

    import UIKit
    
    
    class MyTableViewCell: UITableViewCell {
    
        var delegate: myTableDelegate?
    
        override func awakeFromNib() {
            super.awakeFromNib()
    
            let tapGesture = UITapGestureRecognizer(target: self, action: #selector(MyTableViewCell.tapEdit(_:)))
            addGestureRecognizer(tapGesture)
            //tapGesture.delegate = ViewController()
    
        }
    
        func tapEdit(sender: UITapGestureRecognizer) {
            delegate?.myTableDelegate()
        }
    
    }
    
    protocol myTableDelegate {
        func myTableDelegate() 
    }
    

    In your viewController:

    import UIKit
    
    class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UIGestureRecognizerDelegate, myTableDelegate {
    
        @IBOutlet var tableView: UITableView!
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            tableView.delegate = self
            tableView.dataSource = self
            // Do any additional setup after loading the view, typically from a nib.
        }
    
        func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return 35
        }
    
        func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as? MyTableViewCell
    
            cell?.delegate = self
    
            return cell!
        }
    
        func myTableDelegate() {
            print("tapped")
            //modify your datasource here
        }
    
    }
    

    However, this method could cause problems, see UIGestureRecognizer and UITableViewCell issue. In this case, when the swipe gesture successes, the selector get called twice for some reason. I can't say the second method is a bad one as I haven't found any direct evidence yet, but after searching through Google, it seems like the first method is the standard way.

    0 讨论(0)
提交回复
热议问题