【问题标题】:Collection View Cell Button not triggering action集合视图单元格按钮未触发操作
【发布时间】:2017-04-20 17:11:07
【问题描述】:

所以我在集合视图单元格 xib 中有一个看起来像铅笔的按钮。

然后我有这个代码。

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "groupsCollectionViewCellIdentifier", for: indexPath) as! GroupCollectionViewCell

    //add action to the edit button
    cell.editButton.tag = indexPath.row
    cell.editButton.addTarget(self, action: #selector(GroupsCollectionViewController.editGroupAction), for: .touchUpInside)

    return cell
}

//segue to edit group
func editGroupAction() {
    performSegue(withIdentifier: "editGroupSegue", sender: self)
}

但是每当我点击编辑按钮时。什么都没有发生。我想知道缺少什么。

【问题讨论】:

    标签: swift xcode uibutton uicollectionview uicollectionviewcell


    【解决方案1】:

    我花了好几个小时在网上搜索我的 UIButton 在 UICollectionView 中不起作用的解决方案。让我发疯,直到我终于找到适合我的解决方案。而且我相信这也是正确的方法:破解命中测试。这是一个比修复 UICollectionView 按钮问题更深入(双关语)的解决方案,因为它可以帮助您将点击事件发送到隐藏在阻止您的事件通过的其他视图下的任何按钮:

    UIButton in cell in collection view not receiving touch up inside event

    由于 SO 答案在 Objective C 中,我从那里找到了一个快速解决方案的线索:

    http://khanlou.com/2018/09/hacking-hit-tests/

    --

    当我禁用单元格上的用户交互或我尝试的任何其他各种答案时,都没有任何效果。

    我在上面发布的解决方案的美妙之处在于,您可以保留 addTarget 和选择器函数的习惯,因为它们很可能永远不会成为问题。您只需要重写一个函数来帮助触摸事件到达目的地。

    解决方案为何有效:

    在最初的几个小时里,我发现我的 addTarget 调用没有正确注册手势。事实证明,目标注册良好。触摸事件根本就没有到达我的按钮。

    现实似乎来自我阅读的任何数量的 SO 帖子和文章,即 UICollectionView 单元旨在容纳一个动作,而不是出于各种原因的多个动作。所以你只是应该使用内置的选择动作。考虑到这一点,我相信绕过此限制的正确方法不是破解 UICollectionView 以禁用滚动或用户交互的某些方面。 UICollectionView 只是在做它的工作。 正确的方法是破解命中测试以在点击到达 UICollectionView 之前拦截点击并找出他们正在点击的项目。然后,您只需向他们正在点击的按钮发送一个触摸事件,然后让您的正常工作完成。


    我的最终解决方案(来自 khanlou.com 文章)是将我的 addTarget 声明和我的选择器函数放在我喜欢的任何位置(在单元格类或 cellForItemAt 覆盖中),并在覆盖 hitTest 函数的单元格类中。

    在我的单元班中,我有:

    @objc func didTapMyButton(sender:UIButton!) {
        print("Tapped it!")
    }
    

    override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
    
        guard isUserInteractionEnabled else { return nil }
    
        guard !isHidden else { return nil }
    
        guard alpha >= 0.01 else { return nil }
    
        guard self.point(inside: point, with: event) else { return nil }
    
    
        // add one of these blocks for each button in our collection view cell we want to actually work
        if self.myButton.point(inside: convert(point, to: myButton), with: event) {
            return self.myButton
        }
    
        return super.hitTest(point, with: event)
    }
    

    在我的单元类初始化中,我有:

    self.myButton.addTarget(self, action: #selector(didTapMyButton), for: .touchUpInside)
    

    【讨论】:

    • 天啊。你拯救了我的一天
    • 哇,非常感谢您和 Khanlou!自 iOS 14 发布以来,我们的一个应用程序就被破坏了。
    • 非常感谢!我在 iOS 15 上没有任何问题,但使用 iOS 12 的用户抱怨按钮不起作用。按照您的建议实施命中测试可以解决问题,并且它在 iOS 15 上也能按预期工作。
    【解决方案2】:

    在你的手机上试试这个

    cell.contentView.isUserInteractionEnabled = false
    

    【讨论】:

    • 这里什么是内容视图?它是默认名称还是任何按钮名称?
    • 那是你的细胞
    【解决方案3】:

    考虑到您的问题,我创建了一个演示,其中包含您在上面提供的详细信息,并进行了一些小改动。
    我已经修改了您的 cellForItem 方法。我的修改版本如下。

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell : GroupCollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: "groupsCollectionViewCellIdentifier", for: indexPath) as! GroupCollectionViewCell
    
    
        cell.editButton.tag = indexPath.row
        cell.editButton.addTarget(self, action: #selector(editGroupAction(sender:)), for: .touchUpInside)
    
        return cell
    }
    


    动作方法如下:

    func editGroupAction(sender: UIButton) {
        print("Button \(sender.tag) Clicked")
    }
    


    从您的代码中,我修改了以下详细信息:
    1)UICollectionViewCellObject的声明方式。
    2) 将#Selector 方法分配给UIButton 的方式。最后
    3) 在操作方法中,我打印了 Button 标签。

    通过上述更改,我得到了正确的结果。我将选定的索引值作为按钮标记,在 consol 中的代码中分配。我得到的输出如下。

    Button 2 Clicked
    Button 3 Clicked
    Button 4 Clicked
    

    我希望这能满足您的要求。

    【讨论】:

      【解决方案4】:

      我遇到了同样的问题,在使用视图层次结构后,我注意到单元格中添加了一个额外的UIView。 这个视图在我的UIButton上方,所以触摸事件没有传递给按钮,而是触发了didSelectItem

      我通过使用以下调用解决了这个问题:

      cell.bringSubviewToFront(cell.button)
      

      现在将调用该事件。

      【讨论】:

        【解决方案5】:

        要在自定义 UICollectionCell 的 UIButton 上启用触摸操作,请在自定义 UICollectionCell 类中添加以下方法。

        override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
            var view = myButton.hitTest(myButton.convert(point, from: self), with: event)
            if view == nil {
                view = super.hitTest(point, with: event)
            }
        
            return view
        }
        

        如果你必须覆盖多个按钮,这里有一种编写相同代码的方法:

        class SomeCell: UICollectionViewCell {
        
          @IBOutlet var drawButton: UIButton?
          @IBOutlet var buyButton: UIButton?
          @IBOutlet var likeButton: UIButton?
          @IBOutlet var sayButton: UIButton?
        
          // fix crazy Apple bug in collection view cells:
        
         override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
        
            if let drawButton = drawButton, let v = drawButton.hitTest(
                      drawButton.convert(point, from: self), with: event) {
                return v
            }
        
            if let buyButton = buyButton, let v = buyButton.hitTest(
                     buyButton.convert(point, from: self), with: event) {
                return v
            }
        
            if let likeButton = likeButton, let v = likeButton.hitTest(
                     likeButton.convert(point, from: self), with: event) {
                return v
            }
        
            // etc ...
        
            return super.hitTest(point, with: event)
         }
        }
        

        【讨论】:

        • 谢谢,搜索了很长时间,这对我有用。
        • 这是正确答案!苹果真讨厌。
        【解决方案6】:

        如果您以编程方式声明按钮,则需要确保将它们设置为 lazy var 对象,以确保在初始化按钮之前首先完全定义 self

        
        class myCell: UICollectionViewCell {
        
          static let identifier = "myCellId"
        
          lazy var myButton: UIButton = {
            let btn = UIButton()
            btn.addTarget(self, action: #selector(handleButtonPress(_:)), for .touchUpInside)
            return btn
          }()
        
          // rest of cell 
        
        }
        
        

        【讨论】:

        • 为什么推荐这个?
        • @SafeFastExpressive 以便在创建按钮之前完全定义self
        【解决方案7】:

        您是否将类分配给单元格并将按钮与控制器链接,并将标识符分配给segue,并使用断点检查函数是否被调用

        并像这样使用segue

        func editGroupAction() {
            performSegue(withIdentifier: "editGroupSegue", sender: self)
            let src = self.sourceViewController as UIViewController
            let dst = self.destinationViewController as UIViewController
            src.navigationController.pushViewController(dst, animated:false)
        }
        

        【讨论】:

        • 我已经为cell分配了类,Segue也有一个标识符。
        • 所以在断点它甚至没有调用函数。点击按钮什么都不做。
        • 所以现在你检查你是否将按钮链接到单元格
        • 我确实将按钮作为出口链接到我创建的 CollectionViewCell 类。
        • 然后从 #selector(GroupsCollectionViewController.editGroupAction) 中删除 GroupsCollectionViewController 使用简单
        【解决方案8】:

        如果您使用的是 iOS 10。以下是工作代码

            func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
        
        
                   let cell = collectionView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! YourCellClass
         cell.btnJoin.tag = (indexPath as NSIndexPath).row    
         cell.btnJoin.addTarget(self, action: #selector(YourViewControllerClassName.doSomething(_:)), for: UIControlEvents.touchUpInside)
            }
        

        动作

         func doSomething(_ sender: UIButton)  {
                  print("sender index",sender.tag)
           }
        

        【讨论】:

          【解决方案9】:

          我意识到这张票已经很旧了,但我遇到了同样的问题,并找到了不同的解决方案。

          我使用视图调试器运行 Xcode。虽然按钮的大小正确,但它的超级视图的宽度为 0 点。这将导致无法点击此按钮或任何其他子视图。

          只是提到这一点,因为它可能值得一试。

          【讨论】:

            【解决方案10】:

            顺便说一句,我必须实施命中测试解决方案,然后我遇到了以下问题:

            我有一个类似的问题,我的一个按钮正在工作,而单元格底部的另一个按钮没有工作,它位于堆栈视图中。所以经过几个小时的环顾后,我发现其中一个父视图(在按钮和 CollectionView 本身之间)的大小小于其子视图的大小,在这种情况下,触摸根本没有报告,因为它们是发生在父视图之外......修复了它,它就像一个魅力......

            更具体地说,我为我的集合视图和名为“_UICollectionViewOrthogonalScrollerEmbeddedScrollView”的视图使用了组合布局,它是集合视图单元格的包装器,估计大小小于它自己的单元格

            【讨论】:

              猜你喜欢
              • 2016-07-30
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-04-17
              • 2016-10-11
              • 1970-01-01
              • 2018-01-02
              相关资源
              最近更新 更多