如何向 UITableViewCell 添加手势?

Posted

技术标签:

【中文标题】如何向 UITableViewCell 添加手势?【英文标题】:How to add gesture to UITableViewCell? 【发布时间】:2016-06-08 03:57:55 【问题描述】:

我想为 UITableView 中的每个单元格添加一个点击手势,以编辑其中的内容。添加手势的两种方法是在代码中或通过故事板。我都试过了,都失败了。

我可以通过故事板拖放向表格中的每个单元格添加手势吗?它似乎只向第一个单元格添加手势。在代码中添加手势,我写了类似的东西,

addGestureRecognizer(UITapGestureRecognizer(target: self,action:#selector(MyTableViewCell.tapEdit(_:))))

addGestureRecognizer(UITapGestureRecognizer(target: self, action:"tapEdit:"))

两者都有效。但我想让UITableViewController 处理这个手势,因为它对数据源做了一些事情。如何写下我的目标和行动?

编辑:

addGestureRecognizer(UITapGestureRecognizer(target: MasterTableViewController.self, action:#selector(MasterTableViewController.newTapEdit(_:)))

它会引发一个错误,即无法识别的选择器发送到类 0x106e674e0...

【问题讨论】:

在 UITableViewCell 上添加 UIButton,每个按钮都有唯一的标签号。为按钮分配一种方法。您可以在该方法上获取标签号 【参考方案1】:

要给 UITableViewCell 添加手势,可以按照以下步骤操作:

首先,给 UITableView 添加手势识别器

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

然后,定义选择器。使用recognizer.locationInView 定位您在tableView 中点击的单元格。你可以通过tapIndexPath访问你的dataSource中的数据,这是用户点击的单元格的indexPath。

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

            
        
    

可以直接在TableView单元格中添加手势并访问viewController中的数据源,您需要设置一个委托:

在您的自定义单元格中:

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() 

在您的 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
    


但是,此方法可能会导致问题,请参阅UIGestureRecognizer and UITableViewCell issue。在这种情况下,当滑动手势成功时,选择器会因为某种原因被调用两次。我不能说第二种方法不好,因为我还没有找到任何直接证据,但是通过谷歌搜索后,似乎第一种方法是标准方法。

【讨论】:

将手势添加到 tableViewCell 而不是 tableView 似乎很自然,然后在代码中指定哪个。对于像平移这样更复杂的手势,编写条件检查平移是否在单元格中开始/停留/结束并处理其他情况对我来说可能很痛苦。我想给 tableviewcell 添加手势,在 tableviewcell.swift 中编写代码。是否可以?你能回答我的第二个问题,我如何编写 UITapGestureRecognizer(target, action) 的目标和选择器 目标和选择器let tapGesture = UITapGestureRecognizer(target: self, action: #selector(MyTableViewCell.tapEdit(_:))) 让 tapGesture = UITapGestureRecognizer(target: self, action: #selector(MyTableViewCell.tapEdit(_:))) 工作。但在我的情况下,手势与数据源交互,所以我希望目标是 UITableViewController,并使用其中一个函数(可以改变数据源),怎么做? 谢谢,它有效。出于好奇,目标只能是自我(或属于类的东西)? @FateRiddle No. target 是一个对象,它是接收者在表示的手势发生时发送的动作消息的接收者。您可以多次调用此方法来指定多个目标-动作对。但是,如果您请求添加已添加的目标-操作对,则该请求将被忽略。 “self”这里是你的自定义单元格【参考方案2】:

你不需要添加手势识别器来实现你正在做的事情。

使用UITableViewDelegate 方法tableView:didSelectRowAtIndexPath: 检测哪一行被点击(这正是你的tapGesture 要做的事情),然后进行你想要的处理。 如果您不喜欢选择单元格时的灰色指示,请在返回单元格之前在您的tableView:didEndDisplayingCell:forRowAtIndexPath: 中键入:cell?.selectionStyle = .None

【讨论】:

点击只是一个例子,我喜欢在每个单元格上做各种手势。 你有自定义的单元格类吗? 如果是,则在自定义单元格类的awakeFromNib 方法中添加手势识别器 我就是这么做的,但我不知道如何编写一个使用 TableViewController 中的函数的 UITapGestureRecognizer。如果代码在 myTableViewCell.swift 中的 awakeFromNib 中【参考方案3】:

在 awakeFromNib 方法中添加手势似乎更容易并且效果很好。

class TestCell: UITableViewCell 

    override func awakeFromNib() 
        super.awakeFromNib()

        let panGesture = UIPanGestureRecognizer(target: self,
                                            action: #selector(gestureAction))
        addGestureRecognizer(panGesture)
    

    @objc func gestureAction() 
        print("gesture action")
    

【讨论】:

实例成员“addGestureRecognizer”不能用于类型“TestViewCell”【参考方案4】:

最简单的方法是在自定义UITableViewCell 中添加手势。设置自定义委托模式的一个更简单的替代方法是通知视图控制器编辑将是使用视图控制器可以提供的闭包形式的处理程序,并在用户编辑完成时调用。我假设一个 textField 用于允许单元格编辑。

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?()
    

在您的自定义 UITableViewController 中,传入处理程序以便能够对您的模型进行更改。不要忘记考虑闭包中可能的内存周期。

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

【讨论】:

以上是关于如何向 UITableViewCell 添加手势?的主要内容,如果未能解决你的问题,请参考以下文章

向 UiTableViewCell 添加删除按钮

在 UITableViewCell 的子视图上添加单击和双击手势

RxSwift:如何向 UILabel 添加手势?

如何在 spritekit 中向节点添加滑动手势

滚动时如何向 UITableViewCell 添加更多按钮?

滑动手势在 UITableViewCell 中不起作用