How to ignore touch events and pass them to another subview's UIControl objects?

做~自己de王妃 提交于 2019-11-26 15:08:14

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.

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).

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:

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!

Melkon

You could also disable user interaction so that touch events are ignored and are passed to the parent.

In Swift:

yourView.isUserInteractionEnabled = false

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:

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

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:

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
}

My problem was similar: I had a UIControl with complex touch responders, but it acted funny when embedded in a scroll view...

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.

Call delegate.didBeginInteraction from touchesBegan

Call delegate.didEndInteraction from touchesEnded and touchesCancelled

In parent controller, implement didBegin and didEnd protocol, set delegate

Then set scrollView.scrollEnabled = NO in didBegin, scrollEnabled = YES in didEnd.

Hope this helps someone with a slightly different use case than the question posed!

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!