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

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

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

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

在 UIControl 类型上也是如此。

72725 次浏览

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

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

也许最好的方法是在您希望忽略的视图中覆盖 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;
}

我建议第一种方法是最健壮的(如果可以获得对底层视图的引用的话)。

这是一个古老的问题,它出现在搜索的顶部。所以,我觉得我应该发布另一个可能的解决方案,也许对你的情况更有效。在我的示例中,我希望将一个标签拖到另一个标签的顶部,并且希望在 hitTest 中获得下面的标签。最简单的方法是将 userInteractionEnabled设置为 NOfalse,然后执行命中测试,如果需要再次移动它,则再次将其设置回去。下面是 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
}

快速回答:

可以创建 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,必须将 UserInteractionEnable 设置为 true!

我的问题是相似的: 我有一个复杂的触摸响应器的 UIControl,但它的行为有趣时,嵌入在一个滚动视图..。

当子视图具有活动触摸姿态时,这可以防止父视图滚动(或者可以修改以防止其他交互)。

我的解决办法是:

在子视图中为 did BeginInteractive 和 did EndInteractive 创建一个委托协议。

从触摸开始交互

从 touch 结束和 touch 取消调用 generate.did 结束交互

在父控制器中,实现了 diBegin 和 diEnd 协议,设置了委托

然后在 ddBegin 中设置 scrollView.scrollEnable = NO,在 ddEnd 中设置 scrollEnable = YES。

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

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

斯威夫特:

yourView.isUserInteractionEnabled = false

对我来说,简单的解决方案是在添加到按钮的特定子视图上将 isUserInteractionEnabled设置为 false。

// Some example view components
let button: UIButton = ...
let stackView: UIStackView = ...


// Setting this to false will make all touches ignored by this subview
stackView.isUserInteractionEnabled = false


// Maybe this was my specific case, but I had a pretty custom button with a bunch of subviews.
button.addSubview(stackView)