关于事件响应链、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就行了。
未完。
浙公网安备 33010602011771号