【问题标题】:Tap Gesture Recognizer not received in custom UIView embedded in super view在超级视图中嵌入的自定义 UIView 中未收到点击手势识别器
【发布时间】:2016-05-03 15:00:37
【问题描述】:

我正在尝试创建一个名为 MyScrollView 的自定义 UIView/Scrollview,其中包含一些标签 (UILabel),这些标签接收点击手势/事件以响应用户的选择

为了使点击事件在 UILabel 上起作用,我确保它们都有 userIteractionEnabled = true 并且我创建了一个如下委托:

protocol MyScrollViewDelegate {
    func labelClicked(recognizer: UITapGestureRecognizer)
}

在我创建的ScrollViewController 中使用了自定义 UIView,这个ScrollViewController 也实现了委托方法:

import UIKit
import Neon
class ScrollViewController: UIViewController, MyScrollViewDelegate {

var curQuestion: IPQuestion?
var type: QuestionViewType?
var lastClickedLabelTag: Int = 0 //

init(type: QuestionViewType, question: IPQuestion) {
    super.init(nibName: nil, bundle: nil)
    self.curQuestion = question
    self.type = type
}

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

override func viewDidLoad() {
    super.viewDidLoad()
    self.automaticallyAdjustsScrollViewInsets = false
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
}

override func loadView() {
    view = MyScrollView(delegate: self, q: curQuestion!)
    view.userInteractionEnabled = true
}
}

// implementations for MyScrollViewDelegate
extension ScrollViewController {

func labelTitleArray() -> [String]? {
    print("labelTitleArray called in implemented delegate")

    return ["Comments", "Answers"]
}

func labelClicked(recognizer: UITapGestureRecognizer) {
    print("labelClicked called in implemented delegate")
    let controller = parentViewController as? ParentViewController
    controller?.labelClicked(recognizer)
    lastClickedLabelTag = recognizer.view!.tag
    }
}

// MARK: - handle parent's ViewController event
extension QuestionDetailViewController {
    func updateActiveLabelsColor(index: Int) {
        print("updating active labels color: \(index)")
        if let view = view as? MyScrollView {
            for label in (view.titleScroll.subviews[0].subviews as? [UILabel])! {
                if label.tag == index {
                    label.transform = CGAffineTransformMakeScale(1.1,1.1)
                    label.textColor = UIColor.purpleColor()
                }
                else {
                    label.transform = CGAffineTransformMakeScale(1,1)
                    label.textColor = UIColor.blackColor()
                }
            }
        }
    }
}

上面的ScrollViewController被添加,作为父视图控制器的子视图控制器,并定位到父视图的顶部:

override func viewDidLoad() {
        super.viewDidLoad()
        self.automaticallyAdjustsScrollViewInsets = false
        self.view.backgroundColor = UIColor.whiteColor()
        addChildViewController(scrollViewController) // added as a child view controller here
        view.addSubview(scrollViewController.view) // here .view is MyScrollView
        scrollViewController.view.userInteractionEnabled = true
        scrollViewController.view.anchorToEdge(.Top, padding: 0, width: view.frame.size.width, height: 100)
    }

应用程序可以在视图中加载所有内容,但点击手势/事件不会传递到自定义 MyScrollView 中的标签。为此,我做了一些谷歌搜索,并在 Apple Developer 网站上阅读了 Event Delivery: Responder Chain 并进行了命中测试。下面的hitTest函数可以在MyScrollView中触发:

override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? {
        print("hit test started, point: \(point), event: \(event)")
        return self
    }

我对@9​​87654336@ 的观察是touchesBegan()touchesEnded() 方法在视图中触发hitTest 函数存在时。如果没有hitTest,这两个函数都不会被点击调用。

但没有运气让UILabel 回复点击手势。因此,我在这里联系了有关 SO 的专家。感谢您的帮助!

【问题讨论】:

  • 在父级的相关触摸方法中,尝试将它们转发给下一个响应者。例如,在父级内的touchesBegan 内,尝试调用self.nextResponder.touchesEnded
  • 您是否为您的标签设置了属性 userInteractionEnabled = true ? UILabel 的默认值是 false,所以如果你想接收手势,你应该改变它。
  • @VladimirK,是的,我确实在所有标签上将 userIteractionEnabled 设置为 true。谢谢
  • self.nextResponder()?.touchesEnded() 似乎将事件向上发送,而不是向下发送。问题仍然存在。谢谢
  • 好的,您是否为添加到标签的手势识别器实现了委托方法:gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:?

标签: ios swift events uiview uitapgesturerecognizer


【解决方案1】:

我想我找到了UILabel经过一番挣扎后没有响应点击的原因:标签的.addGestureRecognizer()方法是在我自定义的UIView组件的init()方法中运行的,即错误,因为视图/标签可能还没有被渲染。相反,我将该代码移至生命周期方法layoutSubviews(),一切都开始运行良好:

var lastLabel: UILabel? = nil

        for i in 0..<scrollTitleArr.count {
            let label = UILabel()
            label.text = scrollTitleArr[i] ?? "nothing"
            print("label: \(label.text)")
            label.font = UIFont(name: "System", size: 15)
            label.textColor = (i == 0) ? MaterialColor.grey.lighten2 : MaterialColor.grey.darken2
            label.transform = (i == 0) ? CGAffineTransformMakeScale(1.1, 1.1) : CGAffineTransformMakeScale(0.9, 0.9)
            label.sizeToFit()
            label.tag = i // for tracking the label by tag number
            label.userInteractionEnabled = true
            label.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.labelClicked(_:))))

            titleContainer.addSubview(label)

            if lastLabel == nil {
                label.anchorInCorner(.TopLeft, xPad: 0, yPad: 0, width: 85, height: 40)
      //         label.anchorToEdge(.Left, padding: 2, width: 85, height: 40)
            } else {
                label.align(.ToTheRightMatchingTop, relativeTo: lastLabel!, padding: labelHorizontalGap, width: 85, height: 40)
            }

            lastLabel = label

        }

此外,我不需要实现任何 UIGestureRecognizer 委托方法,也不需要制作容器视图或滚动视图userInteractionEnabled。更重要的是,在将自定义 UIView 嵌入到 superview 时,我配置了它的大小并设置了clipsToBounds = true

我想我应该在 Apple Developer 网站上阅读更多 UIView 文档。希望这对将来像我这样的人有所帮助!谢谢大家!

【讨论】:

    【解决方案2】:

    你必须设置属性userInteractionEnabled = YES

    【讨论】:

      【解决方案3】:

      由于某种原因,当点击手势识别器无法正常工作时,我的模拟器被冻结或其他原因。因此,当我重新启动该应用程序时,一切都恢复了。我不知道这是否适用于此,但这对我来说是解决方法。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-06-25
        • 1970-01-01
        • 1970-01-01
        • 2021-09-27
        • 1970-01-01
        相关资源
        最近更新 更多