xcode 从 UIGestureRecognizer 中排除子视图

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15457205/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 03:00:09  来源:igfitidea点击:

Exclude subviews from UIGestureRecognizer

objective-cxcodeuiviewuigesturerecognizer

提问by Awais Hussain

I have a UIView (the 'container view') which contains several 'sub views'. I want to add a UITapGestureRecognizer to the container view, such that it is activated when I touch the region inside the container view but outside the subviews.

我有一个 UIView(“容器视图”),其中包含几个“子视图”。我想向容器视图添加一个 UITapGestureRecognizer,这样当我触摸容器视图内但子视图外的区域时它会被激活。

At the moment, touching anywhere inside the container view, including inside the subviews activates the gesture recognizer.

目前,触摸容器视图内的任何地方,包括子视图内,都会激活手势识别器。

The implementation looks something like this: In the controller:

实现看起来像这样: 在控制器中:

ContainerView *containerView = [[ContainerView alloc] initWithSubViews:array];
UITapGestureRecognizer *tap = [UITapGestureRecognizer alloc] initWithTarget:self action:@selector(someSelector)];
[containerView addGestureRecognizer:tap];
[self.view addSubView:containerView];

In ContainerView.m

在 ContainerView.m

-(id)initWithSubviews:(NSArray *)array {
    for (subView *s in array) {
        [self addSubView:s];
    }
    return self;
}

I think the problem occurs because the gesture recognizer is added after the subviews are. If that is true then the solution would require breaking the initWithSubViews method into two separate ones, which I would prefer to avoid.

我认为出现问题是因为在子视图之后添加了手势识别器。如果这是真的,那么解决方案需要将 initWithSubViews 方法分成两个独立的方法,我宁愿避免这种情况。

Thank You

谢谢你

采纳答案by matt

iOS 6 introduces a great new feature that solves this exact problem - a UIView (subview) can return NO from gestureRecognizerShouldBegin:(gesture recognizer attached to a superview). Indeed, that is the default for some UIView subclasses with regard to some gesture recognizers already (e.g. a UIButton with regard to a UITapGestureRecognizer attached to a superview).

iOS 6 引入了一个很棒的新功能来解决这个确切的问题 - UIView(子视图)可以从gestureRecognizerShouldBegin:(附加到超级视图的手势识别器)返回 NO 。事实上,对于某些已经存在的手势识别器而言,这是某些 UIView 子类的默认设置(例如,对于附加到超视图的 UITapGestureRecognizer 而言的 UIButton)。

See my book on this topic: http://www.apeth.com/iOSBook/ch18.html#_gesture_recognizers

请参阅我关于此主题的书:http: //www.apeth.com/iOSBook/ch18.html#_gesture_recognizers

回答by vietstone

I used the simple way below. It works perpectly!

我使用了下面的简单方法。它完美地工作!

Implement UIGestureRecognizerDelegate function, accept only touchs on superview, not accept touchs on subviews:

实现 UIGestureRecognizerDelegate 函数,只接受父视图的触摸,不接受子视图的触摸:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
    if (touch.view != _mySuperView) { // accept only touchs on superview, not accept touchs on subviews
        return NO;
    }

    return YES;
}

回答by Awais Hussain

I managed to get it working by doing the following:

我设法通过执行以下操作使其正常工作:

UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapGestureHandler:)];

// ...

-(void) tapGestureHandler:(UITapGestureRecognizer *)sender {
    CGPoint point = [sender locationInView:sender.view];
    UIView *viewTouched = [sender.view hitTest:point withEvent:nil];
    if ([viewTouched isKindOfClass:[ThingIDontWantTouched class]]) {
        // Do nothing;
    } else {
        // respond to touch action
    }
}

回答by Jim Tierney

Remember to add and set the delegate method-

记得添加和设置委托方法——

In your UIViewController's .h file include this delegate

在你的 UIViewController 的 .h 文件中包含这个委托

@interface YourViewController: UIViewController<UIGestureRecogniserDelegate>

Then where you're creating your tapGesture object, (within viewDidLoad for example)

然后你在哪里创建你的 tapGesture 对象,(例如在 viewDidLoad 中)

    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(actionMethodYouWantToHappenOnTap)];  

    tap.delegate = self;  //Remember to set delegate! Otherwise the delegate method won't get called.

    [self.view addGestureRecognizer:tap];

Remembering to set the delegate method tap.delegate = self;then the delegate method for tap will now fire on tap.

记住设置委托方法,tap.delegate = self;然后点击的委托方法现在将在点击时触发。

Within this method you handle when you would like the tap gesture recognition to be used, in my code I wanted it to ignore a tap if a particular subview was visible

在此方法中,您可以处理何时希望使用点击手势识别,在我的代码中,如果特定子视图可见,我希望它忽略点击

-(BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{

     if (!mySubview.hidden){
     return NO;   //This fired if said subview was visible, though whatever the condition of where and when you want tap to work, can be handled within this delegate method.
     }

    return YES;
}

I hope this helps anyone else with the same issue. Remembering to set the delegate method I found was something that's easily overlooked.

我希望这可以帮助其他有同样问题的人。记住设置我发现的委托方法很容易被忽视。

Cheers

干杯

回答by Koushik Ravikumar

Lots of answers, adding another alternate solution. Initialise the view tag of the subviews you don't want to receive touches from as 1 and do the following:

很多答案,添加另一个替代解决方案。将您不想接收触摸的子视图的视图标记初始化为 1 并执行以下操作:

- (void)viewDidLoad {
    [super viewDidLoad];
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)];
    tap.delegate = self;
    [self.view addGestureRecognizer:tap];
}

-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
    if (touch.view.tag == 1) {
        return NO;
    }
    return YES;
}

-(void)handleTap:(id)sender
{
//Handle tap...
}

This way, the touch gesture will be received only from the views you require it from.

这样,触摸手势将仅从您需要它的视图中接收。

回答by abdul sathar

Updated Answer for Swift 4

Swift 4 的更新答案

func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
        if touch.view != yourView
        {
            return false
        }

        return true
    }

Before that make sure you have setting delegate property to your object ..

在此之前,请确保您已将委托属性设置为您的对象..

回答by Shamsudheen TK

If you added UITapGestureRecognizerfor ContainerView, it should respond with all over ContainerView. It will not mind its subviews.

如果您UITapGestureRecognizer为 ContainerView添加,它应该响应整个 ContainerView。它不会介意它的子视图。

Check the Gesture location, if its in your subview position,just skip the gesture actions.

检查手势位置,如果它在您的子视图位置,只需跳过手势操作。

- (void) tapGestureHandler:(UIGestureRecognizer *) gestureRecognizer {


    CGPoint tapPoint = [gestureRecognizer locationInView:nil]; 

   //check your tapPoint contains ur subview frame, skip.else do ur actions
}

回答by tzl

ADDED:

添加:

i just thought of something better.

我只是想到了更好的东西。

in your handler

在你的处理程序中

-(void)tapGestureHandler:(UITapGestureHandler)gesture

check if gesture.view is the superview. it will return the subviews if subviews are tapped.

检查gesture.view 是否是超级视图。如果子视图被点击,它将返回子视图。

====================================================

================================================== ==

I would suggest overriding within the superview.

我建议在超级视图中覆盖。

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

this is called to determine if a gesture falls within a view

调用此方法以确定手势是否属于视图

see the answer to this question to see how it behaves by default.

请参阅此问题的答案以了解默认情况下它的行为方式。

Event handling for iOS - how hitTest:withEvent: and pointInside:withEvent: are related?

iOS 的事件处理 - hitTest:withEvent: 和 pointInside:withEvent: 是如何相关的?

you can check if the point is in any of its subviews. if yes, return nil, else return self.

您可以检查该点是否在其任何子视图中。如果是,返回 nil,否则返回 self。

OR

或者

in each of the subviews, add a tapgesture recognizer that does nothing. the gesture recognizer of a subview will cancel the gesture recognizer of its superview by default. i would keep an eye on the memory footprint if there are many subviews though.

在每个子视图中,添加一个不执行任何操作的 Tapgesture 识别器。子视图的手势识别器默认会取消其父视图的手势识别器。如果有很多子视图,我会留意内存占用。