ios 如何忽略触摸事件并将它们传递给另一个子视图的 UIControl 对象?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7719412/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to ignore touch events and pass them to another subview's UIControl objects?
提问by Chris C
I have a custom UIViewController whose UIView takes up a corner of the screen, but most of it is transparent except for the parts of it that have some buttons and stuff on it. Due to the layout of the objects on that view, the view's frame can cover up some buttons beneath it. I want to be able to ignore any touches on that view if they aren't touching anything important on it, but I seem to only be able to pass along actual touch events (touchesEnded/nextResponder stuff). If I have a UIButton or something like that which doesnt use touchesEnded, how do I pass the touch event along to that?
我有一个自定义的 UIViewController,它的 UIView 占据了屏幕的一角,但除了上面有一些按钮和东西的部分之外,它的大部分都是透明的。由于该视图上对象的布局,视图的框架可以覆盖其下方的一些按钮。如果他们没有触及任何重要的内容,我希望能够忽略对该视图的任何触摸,但我似乎只能传递实际的触摸事件(touchesEnded/nextResponder 内容)。如果我有一个不使用 touchesEnded 的 UIButton 或类似的东西,我如何将触摸事件传递给它?
I can't just manually figure out button selector to call, because this custom ViewController can be used on many different views. I basically need a way to call this:
我不能只是手动找出要调用的按钮选择器,因为这个自定义 ViewController 可以用于许多不同的视图。我基本上需要一种方法来调用它:
[self.nextResponder touchesEnded:touches withEvent:event];
[self.nextResponder touchesEnded:touches withEvent:event];
on UIControl types as well.
UIControl 类型也是如此。
回答by Stuart
Probably the best way to do this is to override hitTest:withEvent:
in the view that you want to be ignoring touches. Depending on the complexity of your view hierarchy, there are a couple of easy ways to do this.
可能最好的方法是hitTest:withEvent:
在您想要忽略触摸的视图中覆盖。根据视图层次结构的复杂性,有几种简单的方法可以做到这一点。
If you have a reference to the view underneath the view to ignore:
如果您有对视图下方视图的引用要忽略:
- (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;
}
If you don't have a reference to the view:
如果您没有对视图的引用:
- (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;
}
I would recommend the first approach as being the most robust (if it's possible to obtain a reference to the underlying view).
我会推荐第一种方法是最健壮的(如果有可能获得对基础视图的引用)。
回答by Melkon
You could also disable user interaction so that touch events are ignored and are passed to the parent.
您还可以禁用用户交互,以便忽略触摸事件并将其传递给父级。
In Swift:
在斯威夫特:
yourView.isUserInteractionEnabled = false
回答by Kevin
Swift answer:
迅捷回答:
You can create a UIView subclass, IgnoreTouchView. In a storyboard, set it on the VC's view(s) you want to pass through touches:
您可以创建一个 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
}
}
Note that you must set UserInteractionEnabled to true, for the UIView in question!
请注意,对于有问题的 UIView,您必须将 UserInteractionEnabled 设置为 true!
回答by EricS
I haven't found a good way to pass UITouch events between objects. What usually works better is to implement hitTest and return nil if the point isn't in the view that you want to handle it:
我还没有找到在对象之间传递 UITouch 事件的好方法。通常效果更好的是实现 hitTest 并返回 nil 如果该点不在您想要处理的视图中:
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
回答by smileBot
This is an old question, and it comes up at the top of searches. So, I thought I'd post another possible solution that might work better for your situation. In my case I wanted to drag a label on top of another label and I wanted to get the label below in the hitTest. The simplest thing to do is to set the userInteractionEnabled
to NO
or false
, then do your hitTest, and then set it back again if you need to move it again. Here's a code sample in Swift:
这是一个老问题,它出现在搜索的顶部。所以,我想我会发布另一种可能的解决方案,它可能更适合您的情况。在我的情况下,我想将一个标签拖到另一个标签的顶部,并且我想在 hitTest 中获得下面的标签。最简单的做法是将 设置userInteractionEnabled
为NO
or false
,然后进行 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
}
回答by Lytic
My problem was similar: I had a UIControl with complex touch responders, but it acted funny when embedded in a scroll view...
我的问题很相似:我有一个带有复杂触摸响应器的 UIControl,但是当嵌入滚动视图时它表现得很有趣......
This prevents parent scrolling (or can be modified to prevent other interactions) when sub view has an active touch gesture.
当子视图具有活动触摸手势时,这可以防止父滚动(或可以修改以防止其他交互)。
My solution:
我的解决方案:
Create a delegate protocol for didBeginInteraction and didEndInteraction in sub view.
在子视图中为 didBeginInteraction 和 didEndInteraction 创建委托协议。
Call delegate.didBeginInteraction from touchesBegan
从 touchesBegan 调用 delegate.didBeginInteraction
Call delegate.didEndInteraction from touchesEnded and touchesCancelled
从 touchesEnded 和 touchesCancelled 调用 delegate.didEndInteraction
In parent controller, implement didBegin and didEnd protocol, set delegate
在父控制器中,实现 didBegin 和 didEnd 协议,设置委托
Then set scrollView.scrollEnabled = NO in didBegin, scrollEnabled = YES in didEnd.
然后在 didBegin 中设置 scrollView.scrollEnabled = NO,在 didEnd 中设置 scrollEnabled = YES。
Hope this helps someone with a slightly different use case than the question posed!
希望这可以帮助那些用例与提出的问题略有不同的人!
回答by witek bobrowski
Easies solution for me was setting isUserInteractionEnabled
to false on specific subviews added to a button.
对我来说简单的解决方案是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)