2011-10-10 62 views
55

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

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

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

上UIControl类型

为好。

回答

120

可能做到这一点的最好办法是在视图覆盖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; 
} 

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

+0

这似乎是我想要做的,但我想忽略触摸的视图是我创建的UIViewController的视图属性,所以有没有办法来重写该视图的hitTest函数? –

+4

@chris:好的,只需将其子类化并如上所示使用重写的方法。这意味着你会有一个额外的'.h'和'.m'文件,里面只有很少的代码,但它会完成这项工作。另外,passthrough视图是您的工具包中有用的子类。如果您的视图控制器在'nib'中创建视图,只需进入IB文件并将视图的类更改为身份检查器中的新子类。如果它是以编程方式创建的,则在'loadView'中创建并分配您的视图子类(请参阅编辑)。 – Stuart

+0

精彩的建议!我一直在寻找一个好的解决方案一整天。谢谢。 – Judioo

7

我还没有找到在对象之间传递UITouch事件的好方法。通常什么工作得更好,是落实则hitTest,如果点不在,你要处理它的视图返回nil:

​​
3

这是一个老问题,它出现在搜索的顶部。所以,我想我会发布另一个可能的解决方案,可能会更好地适合您的情况。在我的情况下,我想将标签拖放到另一个标签的顶部,我想在hitTest中获取下面的标签。最简单的做法是将userInteractionEnabled设置为NOfalse,然后执行hitTest,如果需要再次移动,请将其重新设置。下面是斯威夫特一个代码示例:

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 
} 
+0

感谢您的解决方案。 – Hiren

+0

这样做不起作用,因为一旦将label1.userInteractionEnabled设置为false,那么label1以后甚至都不会检测到触摸。 –

+0

@FredA。这就是为什么我写道:“......如果需要再次移动,请将其重新设置”。也许我还不够清楚? – smileBot

8

斯威夫特答案:

您可以创建一个UIView子类,IgnoreTouchView。在故事板,把它放在你想通过接触VC的看法(S):

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

请注意,您必须在问题设置UserInteractionEnabled为真,为UIView的!

+0

凯文,我编辑了几个字符到最新的Swift版本,April2017。 (随意更改等)干杯 – Fattie

0

我的问题是相似的:我有复杂的触摸响应者UIControl,而是嵌入在一个滚动视图,当它作用好笑......

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

我的解决办法:

创建子视图didBeginInteraction和didEndInteraction委托协议。从touchesEnded从的touchesBegan

呼叫delegate.didBeginInteraction

呼叫delegate.didEndInteraction和touchesCancelled

在父控制器,实施didBegin和didEnd协议,设定代表

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

希望这可以帮助某个用户提供与提出的问题略有不同的用例!

相关问题