(七)UIControl

2019-03-01  本文已影响0人  小白猿

本文系转载,原文地址为iOS触摸事件全家桶

UIControl是系统提供的能够以target-action模式处理触摸事件的控件,iOS中UIButton、UISegmentedControl、UISwitch等控件都是UIControl的子类。当UIControl跟踪到触摸事件时,会向其上添加的target发送事件以执行action。值得注意的是,UIConotrol是UIView的子类,因此本身也具备UIResponder应有的身份。

关于UIControl,此处介绍两点:

  1. target-action执行时机及过程
  2. 触摸事件优先级

target-action

UIControl作为能够响应事件的控件,必然也需要待事件交互符合条件时才去响应,因此也会跟踪事件发生的过程。不同于UIResponder以及UIGestureRecognizer通过 touches 系列方法跟踪,UIControl有其独特的跟踪方式:

- (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(nullable UIEvent *)event;
- (BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(nullable UIEvent *)event;
- (void)endTrackingWithTouch:(nullable UITouch *)touch withEvent:(nullable UIEvent *)event;
- (void)cancelTrackingWithEvent:(nullable UIEvent *)event;

乍一看,这4个方法和UIResponder的那4个方法几乎吻合,只不过UIControl只能接收单点触控,因此接收的参数是单个UITouch对象。这几个方法的职能也和UIResponder一致,用来跟踪触摸的开始、滑动、结束、取消。不过,UIControl本身也是UIResponder,因此同样有 touches 系列的4个方法。事实上,UIControl的 Tracking 系列方法是在 touch 系列方法内部调用的。比如 beginTrackingWithTouch 是在 touchesBegan 方法内部调用的, 因此它虽然也是UIResponder,但 touches 系列方法的默认实现和UIResponder本类还是有区别的。

当UIControl跟踪事件的过程中,识别出事件交互符合响应条件,就会触发target-action进行响应。UIControl控件通过 addTarget:action:forControlEvents: 添加事件处理的target和action,当事件发生时,UIControl通知target执行对应的action。说是“通知”其实很笼统,事实上这里有个action传递的过程。当UIControl监听到需要处理的交互事件时,会调用 sendAction:to:forEvent: 将target、action以及event对象发送给全局应用,Application对象再通过 sendAction:to:from:forEvent: 向target发送action。

image

因此,可以通过重写UIControl的 sendAction:to:forEvent:sendAction:to:from:forEvent: 自定义事件执行的target及action。

另外,若不指定target,即 addTarget:action:forControlEvents: 时target传空,那么当事件发生时,Application会在响应链上从上往下寻找能响应action的对象。官方说明如下:

If you specify nil for the target object, the control searches the responder chain for an object that defines the specified action method.

触摸事件优先级

当原本关系已经错综复杂的UIGestureRecognizer和UIResponder之间又冒出一个UIControl,又会摩擦出什么样的火花呢?

In iOS 6.0 and later, default control actions prevent overlapping gesture recognizer behavior. For example, the default action for a button is a single tap. If you have a single tap gesture recognizer attached to a button’s parent view, and the user taps the button, then the button’s action method receives the touch event instead of the gesture recognizer.This applies only to gesture recognition that overlaps the default action for a control, which includes:

  • A single finger single tap on a UIButton, UISwitch, UIStepper, UISegmentedControl, and UIPageControl.
  • A single finger swipe on the knob of a UISlider, in a direction parallel to the slider.
  • A single finger pan gesture on the knob of a UISwitch, in a direction parallel to the switch.

简单理解:UIControl会阻止父视图上的手势识别器行为,也就是UIControl处理事件的优先级比UIGestureRecognizer高,但前提是相比于父视图上的手势识别器。

image

TODO:
上述过程中,手势识别器在执行touchesEnded时是根据什么将状态置为ended还是failed的?即根据什么判断应当识别成功还是识别失败?

纠正 2017.11.17

以上所述UIControl的响应优先级比手势识别器高的说法不准确,准确地说只适用于系统提供的有默认action操作的UIControl,例如UIbutton、UISwitch等的单击,而对于自定义的UIControl,经验证,响应优先级比手势识别器低。读者可自行验证,感谢 @闫仕伟 同学的纠正。

下一篇 (八)解释栗子

上一篇 下一篇

猜你喜欢

热点阅读