关于事件响应链、UIResponder、hitTest

项目中遇到一个问题,在子视图subView上空白区域点击,在特定位置,会触发其父视图的事件。

关于解决方法,我首先想到的是:使用    self.userInteractionEnabled = NO;

经过测试,在父视图上设为NO,子视图所有的屏幕事件都不会响应。然后我搜索一下,发现了

-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event;   这个方法。

UIResponder的事件顺序,首先必须先调用hitTest判断接收事件的view,如果hitTest返回的view不为空,则会把hitTest返回的view作为第一响应者,然后调用

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;

如果有UIGestureRecognizer或者userInteractionEnabled这种优先级高的,就调用

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;

否则,如果中间手指移动什么的,就调用

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;(移出当前view了,就不touchesEnded了,又touchesCancelled)

最后正常完成事件,就调用-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event。

那hitTest工作的时候呢?官方的解释:

This method traverses the view hierarchy by sending the pointInside:withEvent: message to each subview to determine which subview should receive a touch event. If pointInside:withEvent: returns YES, then the subview’s hierarchy is traversed;

 otherwise, its branch of the view hierarchy is ignored.You rarely need to call this method yourself, but you might override it to hide touch events from subviews.

通 过发送PointInside:withEvent:消息给每一个子视图,这个方法遍历视图层树,来决定那个视图应该响应此事件。如果 PointInside:withEvent:返回YES,然后子视图的继承树就会被遍历;否则,视图的继承树就会被忽略。你很少需要调用这个方法,仅仅 需要重载这个方法去隐藏子视图的事件)。从官方的API上的解释,可以看出 hitTest方法中,要先调用 PointInside:withEvent:,看是否要遍历子视图。如果我们不想让某个视图响应事件,只需要重载 PointInside:withEvent:方法,让此方法返回NO就行了。

未完。

 

 

posted @ 2013-08-07 10:02  学长  阅读(412)  评论(0)    收藏  举报