集合视图单元格按钮不触发动作 [英] Collection View Cell Button not triggering action

查看:29
本文介绍了集合视图单元格按钮不触发动作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

然后我有这个代码.

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) ->UICollectionViewCell {let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "groupsCollectionViewCellIdentifier", for: indexPath) as!GroupCollectionViewCell//给编辑按钮添加动作cell.editButton.tag = indexPath.rowcell.editButton.addTarget(self, action: #selector(GroupsCollectionViewController.editGroupAction), for: .touchUpInside)返回单元格}//继续编辑组func editGroupAction() {performSegue(withIdentifier: "editGroupSegue", sender: self)}

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

解决方案

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

集合中单元格中的 UIButton视图未在事件内接收修饰

因为 SO 的答案是在 Objective C 中,所以我按照那里的线索找到了一个快速的解决方案:

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

--

当我禁用单元格上的用户交互或我尝试过的任何其他类型的答案时,没有任何效果.

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

为什么解决方案有效:

在最初的几个小时里,我认为我的 addTarget 调用没有正确注册手势.事实证明,目标注册得很好.触摸事件根本没有到达我的按钮.

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

<小时>

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

在我的单元格类中,我有:

@objc func didTapMyButton(sender:UIButton!) {打印(点击它!")}

override func hitTest(_ point: CGPoint, with event: UIEvent?) ->界面视图?{守卫 isUserInteractionEnabled else { return nil }守卫 !isHidden else { return nil }守卫阿尔法> = 0.01 else {返回零}守卫 self.point(inside: point, with: event) else { return nil }//为我们想要实际工作的集合视图单元格中的每个按钮添加这些块之一if self.myButton.point(inside: convert(point, to: myButton), with: event) {返回 self.myButton}return super.hitTest(point, with: event)}

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

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

So I have a button that looks like a pencil in a collection view cell xib.

Then I have this code.

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

But whenever I click the edit button. Nothing is happening. I wonder what's missing.

解决方案

I spent hours scouring the web for a solution to my UIButton's inside UICollectionView's not working. Driving me nuts until I finally found a solution that works for me. And I believe it's also the proper way to go: hacking the hit tests. It's a solution that can go a lot deeper (pun intended) than fixing the UICollectionView Button issues as well, as it can help you get the click event to any button buried under other views that are blocking your events from getting through:

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

Since that SO answer was in Objective C, I followed the clues from there to find a swift solution:

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

--

When I would disable user interaction on the cell, or any other variety of answers I tried, nothing worked.

The beauty of the solution I posted above is that you can leave your addTarget's and selector functions how you are used to doing them since they were most likey never the problem. You need only override one function to help the touch event make it to its destination.

Why the solution works:

For the first few hours I figured the gesture wasn't being registered properly with my addTarget calls. It turns out the targets were registering fine. The touch events were simply never reaching my buttons.

The reality seems to be from any number of SO posts and articles I read, that UICollectionView Cells were meant to house one action, not multiple for a variety of reasons. So you were only supposed to be using the built in selection actions. With that in mind, I believe the proper way around this limitation is not to hack UICollectionView to disable certain aspects of scrolling or user interaction. UICollectionView is only doing its job. The proper way is to hack the hit tests to intercept the tap before it gets to UICollectionView and figure out which items they were tapping on. Then you simply send a touch event to the button they were tapping on, and let your normal stuff do the work.


My final solution (from the khanlou.com article) is to put my addTarget declaration and my selector function wherever I like (in the cell class or the cellForItemAt override), and in the cell class overriding the hitTest function.

In my cell class I have:

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

and

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

And in my cell class init I have:

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

这篇关于集合视图单元格按钮不触发动作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆