程序员

【重读iOS】各种点击事件的关系

2018-08-02  本文已影响55人  FindCrt

点击事件处理方式的关系

3种处理点击事件的方法:

  1. 手势
  2. touchBegin系列方法
  3. UIControl的addTarget...系列方法

问题:1. 它们之间是否会互相干扰 2. 谁会屏蔽谁 3. UIControl的时间处理本质上是不是还是touch方法 4.手势的原理是什么?它本质是touch方法还是其他的处理系统?5. 如果有互相屏蔽,该怎么避免

测试以及解释

1.不在同一条响应链上

如果这3种方式作用在不同的view上,而这些view之间没有上下级的关系,那么就不存在互相干扰的问题。

点击操作需要找到响应者,确立响应链,不在同一条链上,那么某一个view响应时,完全不会联系到其他的view.

2.control和普通view的touch同一条响应链上

2种方式在不同的view上,但这些view之间具有上下级关系,那么它们就处在同一条响应链上。

现在有3个事件:

测试情况:

总结:

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是否可以处理事件,可惜这里却没有这个方法。甚至在测试例子里canBecomeFirstResponderbecomeFirstResponder都没被调用过。

所以可能的猜测是:把事件传递给上一个响应者的处理,不是一个中心系统处理,而是各个view内部自己决定的,比如UIView默认上传,而UIControl默认不上传。

假设有开放是否可以处理事件的方法,那么会更方便:
想把事件传递给下一个responder,只要return false就可以,如果想截住事件,就return true.

3. control和touch在同一个view上测试
  1. 重写control的touch方法,导致control的的事件无法响应,这个说明了control的事件本质是touch方法
  2. 重写的touch方法如果调用super,control的事件就会重新响应。

结论:control的addTarget系列方法的处理本质还是touch系列方法,在这个基础上加工。

2.1 手势和其他两个共存测试
  1. 普通view和手势,不管哪个在上面,都是手势和touch方法同时响应,而且手势在后面(可能是手势需要判断类型,需要多次触碰才能知道,才会响应,所以延时了)
  2. 手势和按钮一起,手势一定响应,按钮在上面时会响应touchDown,但不会响应touchUpInside
  3. 手势和touch方法在同一个view上时,测试情况跟第1点一样
  4. 手势跟control方法在同一个view上时,手势会起作用,control的addTarget方法会响应touchDown,但不会响应touchUpInside

问题:手势的原理到底是什么 2.响应链跟它们有什么关系

Gesture Recognizers与触摸事件分发

手势跟响应链是不同的系统,对于手势和touch方法的影响,着重理解手势的3个属性:

再回去分析测试效果:

  1. 因为delaysTouchesBegan默认为false,所以touchBegin照常响应,所以普通view的touch和手势都响应了
  2. control在下,这时手势view是hit-test view,手势响应,很正常。control不是所以control的addTarget不响应。control在上时,control响应这个也很正常,但手势还是会响应,而且手势的view和control隔了多个层级还是响应,手势会截取和影响它所有的子view的touch事件,而且它不是完全按照响应链的逻辑来的,手势的view可以不是第一响应者,但还是需要在响应链里,可以是第一响应者的第N个父视图。然后delaysTouchesBegan默认false,所以touchDown会响应,但cancelsTouchesInView默认true,所以手势识别成功后,传送了touchesCancelled,导致按钮事件处理取消,所以touchUpInside不响应。touchUpInside是手指拿起来时判断的,这时按钮的处理已经取消了。
  3. 和第一点相同
  4. 唯一的区别是,现在只有一个view,它一定是hit-test view,相比第3点,不会出现按钮在下没响应的情况,其他的都一样。

系统的文档搜索不到了,Cocoa版在Cocoa Event Handling Guide

总结

  1. 手势是特殊的,分开考虑
  2. control的addTarget系列方法本质是touchBegin系列方法的加工,都属于响应链体系
  3. 响应链体系分两步:第一步找到hit-test view,第二步从hit-test view沿着响应者链找到处理事件的响应者。第一步是没有什么疑问的,第二步关于谁是First Responder,什么时候会转发,“是否可以处理这个事件”这个决定性问题的判断标准是什么等都有疑问。
  4. 对于手势:
  1. control的addTarget系列方法,注意不同event的区别,如touchDown在按下时就决定了,而touchUpInside和touchUpOutside是放手时才决定
  2. 互相影响就只有手势影响其他两个,通过调节3个属性来达到想要的效果。其他两个就按照响应链逻辑,哪个在上面哪个起作用。
上一篇 下一篇

猜你喜欢

热点阅读