首页 文章

如何忽略触摸事件并将它们传递给另一个子视图的UIControl对象?

提问于
浏览
57

我有一个自定义的UIViewController,其UIView占据了屏幕的一角,但大部分都是透明的,除了它的部分有一些按钮和东西 . 由于该视图上对象的布局,视图的框架可以覆盖其下方的一些按钮 . 如果他们没有触及任何重要的东西,我希望能够忽略该视图上的任何触摸,但我似乎只能传递实际的触摸事件(touchesEnded / nextResponder的东西) . 如果我有一个UIButton或类似的东西没有使用touchesEnded,我如何将触摸事件传递给它?

我不能手动找出要调用的按钮选择器,因为这个自定义ViewController可用于许多不同的视图 . 我基本上需要一种方法来调用它:

[self.nextResponder touchesEnded:touches withEvent:event];

在UIControl类型上也是如此 .

6 回答

  • 3

    快速回答:

    您可以创建一个UIView子类IgnoreTouchView . 在故事板中,将其设置在要通过触摸的VC视图上:

    class IgnoreTouchView : UIView {
        override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
            let hitView = super.hitTest(point, with: event)
            if hitView == self {
                return nil
            }
            return hitView
        }
    }
    

    请注意,对于有问题的UIView,您必须将UserInteractionEnabled设置为true!

  • 0

    我的问题很相似:我有一个带有复杂触摸响应器的UIControl,但是当嵌入滚动视图时它表现得很有趣......

    当子视图具有活动的触摸手势时,这可以防止父滚动(或可以修改以防止其他交互) .

    我的解决方案

    在子视图中为didBeginInteraction和didEndInteraction创建委托协议 .

    从touchesBegan调用delegate.didBeginInteraction

    从touchesEnded和touchesCancelled调用delegate.didEndInteraction

    在父控制器中,实现didBegin和didEnd协议,设置委托

    然后在didBegin中设置scrollView.scrollEnabled = NO,在didEnd中设置scrollEnabled = YES .

    希望这可以帮助那些使用案例略有不同的人提出的问题!

  • 128

    可能最好的方法是在视图中覆盖 hitTest:withEvent: ,你想要忽略触摸 . 根据视图层次结构的复杂程度,有几种简单的方法可以做到这一点 .

    如果您对视图下方的视图有引用,则忽略:

    - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
    {
        UIView *hitView = [super hitTest:point withEvent:event];
    
        // If the hitView is THIS view, return the view that you want to receive the touch instead:
        if (hitView == self) {
            return otherView;
        }
        // Else return the hitView (as it could be one of this view's buttons):
        return hitView;
    }
    

    如果您没有对视图的引用:

    - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
    {
        UIView *hitView = [super hitTest:point withEvent:event];
    
        // If the hitView is THIS view, return nil and allow hitTest:withEvent: to
        // continue traversing the hierarchy to find the underlying view.
        if (hitView == self) {
            return nil;
        }
        // Else return the hitView (as it could be one of this view's buttons):
        return hitView;
    }
    

    我建议第一种方法是最强大的(如果可以获得对底层视图的引用) .

  • 7

    我还没有找到一种在对象之间传递UITouch事件的好方法 . 通常更好的方法是实现hitTest并返回nil,如果该点不在您要处理它的视图中:

    - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
    
  • 10

    您还可以禁用用户交互,以便忽略触摸事件并将其传递给父级 .

    In Swift:

    yourView.isUserInteractionEnabled = false
    
  • 3

    这是一个老问题,它出现在搜索的顶部 . 所以,我想我会发布另一种可能更适合你情况的解决方案 . 在我的情况下,我想在另一个标签的顶部拖一个标签,我想在hitTest中获得下面的标签 . 最简单的方法是将 userInteractionEnabled 设置为 NOfalse ,然后执行hitTest,如果需要再次移动,请再次将其设置为 . 这是Swift中的代码示例:

    override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
        let touch = touches.first
        let location = touch?.locationInView(self.view)
        self.label1.userInteractionEnabled = false
        let view = self.view.hitTest(location!, withEvent: nil) as? UILabel
        print(view?.text)
        self.label1.userInteractionEnabled = true
    }
    

相关问题