如何禁用父视图touchBegan事件吗 - How to disable superview touchBegan event

- 此内容更新于:2016-02-02
主题:

我有UIView子类,它要做的是:现在我创建两个MyView实例,一个(C)是50px高,另一个(S)是100px高度。较短的子视图(C)是高(S),他们有不同的背景颜色。然后我运行这个应用程序,点击C,C和S接收touchesBegan事件。我的段,如何防止年代(父视图)接收触摸事件当我点击C?而C是上面(如果C是UIButton的一个实例,它能够正常工作)。下图:当我点击红色的视图中,蓝色的视图和红色视图接收事件,但我希望只有红色视图接收它。当我点击蓝色区域,只有蓝色的视图接收事件,它能够正常工作。——编辑1——这种方法只能如果我只使用MyView,它不会阻止事件传播:——编辑2——看到@TomasCamin发表评论

原文:

I have a UIView subclass, all it has to do is:

@implement MyView
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
    [super touchesBegan:touches withEvent:event];
    NSLog(@"touch began");
}
@end

Now I create two MyView instances, one(C) is 50px height, the other one(S) is 100px height. The shorter one(C) is the subview of the taller one(S), they have diffrent background color.

Then I run the App, and click on the C, both C and S receive touchesBegan event.

My questionis, how do I prevent S(the superview) from receiving touch event when I tap on C? While C is above it(if C is an instance of UIButton, it works as expected).

For the image below:

  • when I tap on the red view, both blue view and red view receive event, but I want only the red view receive it.
  • when I tap on the blue area, only the blue view receive event, it works as expected.

enter image description here

----edited 1----

This method works only if I only use MyView, it does not prevent event propagation:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
    [super touchesBegan:touches withEvent:event];
    UITouch *touch = [touches anyObject];
    if(touch.view != self){
        // ignore the event
        return;
    }
    NSLog(@"touch began");
}

----edited 2----

see @TomasCamin's comment

楼主:像我们一样有什么方法使用javascript在web浏览器,使用javascript,吗

(原文:Is there any method like we do with javascript in a web browser, with javascript, it is event.preventDefault())

网友:实际上它在浏览器。preventDefaultstopPropagation多。

(原文:actually it's event.stopPropagation() in browser. preventDefault does more than stopPropagation.)

网友:我只是试图复制你的问题在iOS8.1但未能这样做。涉及C不传播到年代,除非我打电话的

(原文:I just tried to replicate your issue on iOS 8.1 but failed to do so. Touches on C are not propagated to S, unless I call [super touchesBegan:touches withEvent:event]; in MyView's touchesBegan:touches)

楼主:@TomasCamin我的错误,我失去了在代码中调用snipet,也许我应该测试联系。观点确定whethere(超级touchesBegan)应该被称为。

(原文:@TomasCamin my mistake, I lost the call to [super touchesBegan] in the code snipet, maybe I should test touch.view to determine whethere [super touchesBegan] should be called or not.)

解决方案:

原文:
//your (S) view code
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
  UITouch *touch = [touches anyObject];
  CGPoint location = [touch locationInView:self];
  if (CGRectContainsPoint(yourCView.frame,location))
    return;
}
楼主:它仅仅是行不通的。你必须注意,这两个观点是重叠的。

(原文:It simply doesn't work. You must notice that, the two views are overlapped.)

解决方案:
您可以使用不同的标记每个视图,然后您可以检查使用标签视图是感动。}}
原文:

you can use different tag each of view, then you can check which view is touched using tag.

 - (void)viewDidLoad {
[super viewDidLoad];
  UIView *myView = [[UIView alloc] initWithFrame:CGRectMake(10, 20, 300, 100)];
myView.tag = 100;
myView.backgroundColor = [UIColor blueColor];
[self.view addSubview:myView]; 

}

   -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *toucheObject = [touches anyObject];
if (toucheObject.view.tag == 100) {
    // your code
    NSLog("Your Object Touche");
}

}

楼主:它工作,但是我需要一个共同的解决方案。因为很多时候我们无法为每个视图设置标签。

(原文:It worked, but I need a common solution. Because many times we are not able to set tag for every view.)

解决方案:
你可能要求在我无法复制你报告的问题。如果它适合你的需要我宁愿使用。例如,如果你想拦截丝锥使用子类:
原文:

You're probably calling [super touchesBegan:touches withEvent:event]; inside the [MyView touchBegan:withEvent] as I wasn't able to replicate the problem you're reporting.

If it suits your needs I would rather use a UIGestureRecognizer.

For example if you're trying to intercept just a tap use the UITapGestureRecognizer subclass:

@implementation View

- (id)initWithFrame:(CGRect)frame {
    if ((self = [super initWithFrame:frame])) {
        UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapped:)];
        [self addGestureRecognizer:tap];
    }

    return self;
}

- (void)tapped:(UIGestureRecognizer *)gesture {
    NSLog(@"MyView tapped %p", self);
}

@end
楼主:谢谢,我打电话,但我想念我的问题,现在我补充道。

(原文:Thanks, I was calling [super touchesBegan:touches withEvent:event]; but I got to miss it in my question, now I added it up.)

解决方案:
你有试过UIView.exclusiveTouch吗?编辑:好的,就像我读到外面只有禁用涉及其他视图视图的框架后,用户开始触摸给视图。试图覆盖pointInside:withEvent:返回如果点是在子视图。然后不应该引发了如果你还没有。编辑2:别介意,这也行不通,因为它也会阻止子视图接收触摸。也许你真的应该叫超级只有触及外部子视图:或者你可以描述你试图解决实际问题,也许有更好的解决方案。
原文:

Have you tried UIView.exclusiveTouch?

Edit: Ok, as I've read about UIView.exclusiveTouch it only disables touches on other views outside view's frame after user started touch on given view.

Try to override pointInside:withEvent: to return No if point is inside subview. Then touchesBegan:withEvent: shouldn't be triggered if you return No.

Edit 2: nevermind, this won't work too, because it will block subviews from receiving touches too. Probably you really should call super only if hit is outside subview:

if (self.subviews.count != 0) { // some naive implementation
    [super touchesBegan:touches withEvent:event];
}
NSLog(@"touch began");

Alternatively you can describe actual problem you trying to solve, maybe there is a better solution.

楼主:试过了,父和子视图的事件的时候

(原文:Tried, both parent and subview getting the event when self.exclusiveTouch = YES;)

楼主:谢谢你的耐心的关注。我想构建一个定制的UIView,处理点击事件(不使用UIGuestureRecognizers),一旦子视图处理事件,应该阻止它的父视图处理它。

(原文:Thanks for your patient attention. I want to build a custom UIView, that will deal with Tap event(not using UIGuestureRecognizers), once the subview has handled the event, it should prevent its superview from handling it.)

解决方案:
所有您需要做的就是删除//和可能从其他3触摸事件-移动:结束:取消了:你会得到你想要的。您正在调用的默认实现(通过事件到你的超类)是导致事件继续chain(父视图)
原文:

All you need to do is delete the

 [super touches began:....]

//and probably from the other 3 touch events - moved: ended: cancelled:

And you'll get what you want. The default implementation (which you are invoking by passing the event up to your superclass) is what is causing the event to continue up the responder chain (to the superview)