首页 » iOS编程(第4版) » iOS编程(第4版)全文在线阅读

《iOS编程(第4版)》12.9 深入学习:UIControl

关灯直达底部

UIControl是部分Cocoa Touch类的父类,例如UIButton和UISlider。前面已经介绍过如何为这类UIControl对象设置目标对象和动作方法。学习完触摸事件与UIResponder的相关知识后,本节将进一步介绍UIControl是如何覆盖前面所介绍的那些UIResponder方法的。

对于UIControl对象,每个可能触发的控件事件(control event)都有一个对应的常量。以UIButton对象为例,该对象的常用控件事件是UIControlEventTouchUpInside。如果某个目标对象是针对UIControlEventTouchUpInside注册的,那么只有当用户触摸了这个UIControl对象,并且手指是在该对象的frame区域内离开屏幕时,目标对象才会收到指定的动作消息。因此,可以将控件事件UIControlEventTouchUpInside视为按下操作。

对于UIButton对象,除了UIControlEventTouchUpInside,还可以针对其他事件注册动作消息。例如,假设要完成以下任务:无论用户的手指是在frame区域内离开屏幕,还是在frame区域外离开屏幕,都要触发指定的方法。为了完成这项任务,可以同时注册两个控件事件,示例代码如下:

[rButton addTarget:tempController

action:@selector(resetTemperature:)

forControlEvents:UIControlEventTouchUpInside

| UIControlEventTouchUpOutside];

下面列出UIControl处理UIControlEventTouchUpInside的示例代码。

// 和实际代码不同,实际代码会更复杂一点!

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event

{

// 指针指向已经结束的触摸对象

UITouch *touch = [touches anyObject];

// 触摸结束时的位置(使用当前UIControl对象的坐标系)

CGPoint touchLocation = [touch locationInView:self];

// 结束时的位置是否在视图的bounds区域内?

if (CGRectContainsPoint(self.bounds, touchLocation))

{

// 向注册了UIControlEventTouchUpInside事件的所有目标对象发送动作消息

[self sendActionsForControlEvents:UIControlEventTouchUpInside];

} else {

// 触摸事件是在bounds区域外结束的,

// 所以要向注册了UIControlEventTouchUpOutside事件的所有目标对象发送动作消息

[self sendActionsForControlEvents:UIControlEventTouchUpOutside];

}

}

那么UIControl对象是如何将这些动作消息发送给相应的目标对象的?在上面这段touchesEnded:withEvent:方法的末尾,UIControl对象会向自己发送sendActions- ForControlEvents:消息。该消息会遍历UIControl对象的所有目标-动作对,根据传入的控件事件类型进行查找,然后向匹配的目标对象发送对应的动作消息。

但是,UIControl对象绝对不是直接向目标对象发送消息,而是要通过UIApplication转发。为什么UIControl对象不能直接向目标对象发送动作消息?这是因为在UIControl对象所拥有的目标-动作对中,目标对象可以是nil。UIApplication在转发源自UIControl对象的消息时,会先判断目标对象是不是nil。如果是nil,UIApplication就会先找出UIWindow对象的第一响应对象,然后向第一响应对象发送相应的动作消息。