点击事件处理方式的关系
3种处理点击事件的方法:
- 手势
- touchBegin系列方法
- UIControl的
addTarget...
系列方法
问题:1. 它们之间是否会互相干扰 2. 谁会屏蔽谁 3. UIControl的时间处理本质上是不是还是touch方法 4.手势的原理是什么?它本质是touch方法还是其他的处理系统?5. 如果有互相屏蔽,该怎么避免
测试以及解释
1.不在同一条响应链上
如果这3种方式作用在不同的view上,而这些view之间没有上下级的关系,那么就不存在互相干扰的问题。
点击操作需要找到响应者,确立响应链,不在同一条链上,那么某一个view响应时,完全不会联系到其他的view.
2.control和普通view的touch同一条响应链上
2种方式在不同的view上,但这些view之间具有上下级关系,那么它们就处在同一条响应链上。
现在有3个事件:
- control自身的touch方法
- control的
addTarget
添加的事件 - 普通view的touch方法
测试情况:
- control在下时,addTarget事件不响应,两个view的touch方法都响应,而且control的touch方法是由上层的view转发过去的。
- control在上时,响应control的touch和addTarget事件;如果去掉addTarget事件,就只有control的touch响应
总结:
- touch事件只会传递给hitview,而hit-test view可能会转发给它的nextResponder
- 普通view默认转发,而control不会转发
The hit-test view is given the first opportunity to handle a touch event. If the hit-test view cannot handle an event, the event travels up that view’s chain of responders
The responder chain is a series of linked responder objects. It starts with the first responder
A responder object is an object that can respond to and handle events.
If the first responder cannot handle an event, it forwards the event to the next responder in the responder chain.
注意responder chain包含的是responder objects,而responder objects指的是那些可以处理事件的对象
但最后一段又说first responder可能处理不了事件,真是矛盾。
所以最可能的就是:在概念上hit-test view就是First Responder,也就是第一个检测是否可以处理事件的,而你从代码上,比如调用isFirstResponder
是得不到true
的。
按照响应链的逻辑,最重要的一点是一个responder是否可以处理事件,可惜这里却没有这个方法。甚至在测试例子里canBecomeFirstResponder
和becomeFirstResponder
都没被调用过。
所以可能的猜测是:把事件传递给上一个响应者的处理,不是一个中心系统处理,而是各个view内部自己决定的,比如UIView默认上传,而UIControl默认不上传。
假设有开放是否可以处理事件的方法,那么会更方便:
想把事件传递给下一个responder,只要return false就可以,如果想截住事件,就return true.
3. control和touch在同一个view上测试
- 重写control的touch方法,导致control的的事件无法响应,这个说明了control的事件本质是touch方法
- 重写的touch方法如果调用super,control的事件就会重新响应。
结论:control的addTarget系列方法的处理本质还是touch系列方法,在这个基础上加工。
2.1 手势和其他两个共存测试
- 普通view和手势,不管哪个在上面,都是手势和touch方法同时响应,而且手势在后面(可能是手势需要判断类型,需要多次触碰才能知道,才会响应,所以延时了)
- 手势和按钮一起,手势一定响应,按钮在上面时会响应touchDown,但不会响应touchUpInside
- 手势和touch方法在同一个view上时,测试情况跟第1点一样
- 手势跟control方法在同一个view上时,手势会起作用,control的addTarget方法会响应touchDown,但不会响应touchUpInside
问题:手势的原理到底是什么 2.响应链跟它们有什么关系
手势跟响应链是不同的系统,对于手势和touch方法的影响,着重理解手势的3个属性:
-
cancelsTouchesInView
,手势识别成功,会给hit-view调用touchesCancelled
中断view的事件处理 -
delaysTouchesBegan
,手势识别成功之前,不会给hit-view发送触碰信息,等到手势识别结束,如果成功,则还是不发送,识别失败,照常发送。 -
delaysTouchesEnded
的逻辑和上一个类似,延迟end信息,手势识别成功不发送,识别失败发送。但实际上双击手势符合这个,但滑动手势不符合,它识别成功了还是会发送。
再回去分析测试效果:
- 因为
delaysTouchesBegan
默认为false,所以touchBegin
照常响应,所以普通view的touch和手势都响应了 - control在下,这时手势view是hit-test view,手势响应,很正常。control不是所以control的addTarget不响应。control在上时,control响应这个也很正常,但手势还是会响应,而且手势的view和control隔了多个层级还是响应,手势会截取和影响它所有的子view的touch事件,而且它不是完全按照响应链的逻辑来的,手势的view可以不是第一响应者,但还是需要在响应链里,可以是第一响应者的第N个父视图。然后
delaysTouchesBegan
默认false,所以touchDown会响应,但cancelsTouchesInView
默认true,所以手势识别成功后,传送了touchesCancelled
,导致按钮事件处理取消,所以touchUpInside不响应。touchUpInside是手指拿起来时判断的,这时按钮的处理已经取消了。 - 和第一点相同
- 唯一的区别是,现在只有一个view,它一定是hit-test view,相比第3点,不会出现按钮在下没响应的情况,其他的都一样。
系统的文档搜索不到了,Cocoa版在Cocoa Event Handling Guide
总结
- 手势是特殊的,分开考虑
- control的addTarget系列方法本质是touchBegin系列方法的加工,都属于响应链体系
- 响应链体系分两步:第一步找到hit-test view,第二步从hit-test view沿着响应者链找到处理事件的响应者。第一步是没有什么疑问的,第二步关于谁是First Responder,什么时候会转发,“是否可以处理这个事件”这个决定性问题的判断标准是什么等都有疑问。
- 对于手势:
- 它不仅影响它附在的那个view,还影响这个view图层树里所有的子view.
- 影响手段就抓住理解手势的3个属性:
cancelsTouchesInView ``delaysTouchesBegan ``delaysTouchesEnded
- control的addTarget系列方法,注意不同event的区别,如touchDown在按下时就决定了,而touchUpInside和touchUpOutside是放手时才决定
- 互相影响就只有手势影响其他两个,通过调节3个属性来达到想要的效果。其他两个就按照响应链逻辑,哪个在上面哪个起作用。
网友评论