一天打渔,三天晒网。大家猴又是我,坚持在工作日中的一日一博客。
今天聊的是有关上几篇文章提到的<事件响应链>的后续。在点击Button时,响应事件的背后到底发生了什么事
那提到文章内容前还是得复习一下的
事件传递,响应链到底是怎么样的呢?
至简的回答,传递是自上往下。响应则相反,是自下往上的。
虽然说起来很简单,但是在过程中涉及的方法还是比较多的
传递要经历hitTest,PointInside 等方法遍历控件、定位点的位置
响应要经历nextResponder 方法将父级控件们串联起来进行反馈
其中涉及的很多原理还是实际操作起来更易懂,这里就不在多提了。
往下开始结合代码及日志讲一讲UIButton这个特殊的UIView控件在点击,响应反应的背后
到底发生了什么
在一切的开头,那么肯定得创建一个UIButton对吧,这里简单附上一个方法创建xgButton对象
- (void)createButton{ _xgButton = [[XgButton alloc] initWithFrame:CGRectMake(100, 100, 20.f, 20.f)]; [_xgButton setBackgroundColor:[UIColor redColor]]; [_xgButton addTarget:self action:@selector(action) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:_xgButton]; } - (void)action { NSLog(@"点击事件触发"); }
在Button添加到当前view前绑定了一个单击事件,点击时相应action方法。
因为是触摸的缘故,所以在XgButton中每个touch方法都打印NSLog(@"%s",__func__);查看当前执行顺序。
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { NSLog(@"%s",__func__); [super touchesBegan:touches withEvent:event]; } - (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { NSLog(@"%s",__func__); [super touchesEnded:touches withEvent:event]; } - (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { NSLog(@"%s",__func__); [super touchesMoved:touches withEvent:event]; } - (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { NSLog(@"%s",__func__); [super touchesCancelled:touches withEvent:event]; }
当一切准备就绪后,一切都不明了的情况下,当然是先运行一下程序点击一下xgButton查看下日志到底怎么说吧
2018-12-14 01:16:44.422578+0800 03-Button_Class[31004:2452161] -[XgButton touchesBegan:withEvent:]
2018-12-14 01:16:44.424209+0800 03-Button_Class[31004:2452161] -[XgButton touchesMoved:withEvent:]
2018-12-14 01:16:44.429849+0800 03-Button_Class[31004:2452161] -[XgButton touchesEnded:withEvent:]
2018-12-14 01:16:44.430500+0800 03-Button_Class[31004:2452161] 点击事件触发
咦,在单击事件方法action触发前,Button需要经过touch事件的判断,是否完成当前的控制器事件(ControlEvents)。
当前我们设定的是TouchUpInside,是当我们点击结束后才会响应事件。那如果点击结束TouchesEnd方法里的
[super touchesEnded:touches withEvent:event];
注释了,是不是就无法触发单击事件方法了呢?
验证一下说辞,先把touchesEnded中的传递方法注释了先。然后我们运行下程序验证下结果
2018-12-14 01:23:49.814269+0800 03-Button_Class[31063:2461947] -[XgButton touchesBegan:withEvent:]
2018-12-14 01:23:49.860960+0800 03-Button_Class[31063:2461947] -[XgButton touchesMoved:withEvent:]
2018-12-14 01:23:49.861451+0800 03-Button_Class[31063:2461947] -[XgButton touchesEnded:withEvent:]
结果是打印出来了,但是很明显action事件无法响应了。这说明响应链断了。当前的Button无法通过touchesEnded方法判断自身是否被点击结束了的事实。
所以无法触发action事件。
这说明UIButton在反馈自身被点击的过程中,需要经过touch事件的确定,确定自身是否达到了ControlEvent的要求,比方说本例子中的Button绑定的是单击按钮,松开后。Button能够反馈出与ControlEvent相同的结果时,向控制器证明了当前操作成功了。
以下是小剧场
Button:我被成功的点击了!可以根据这个结果进行正确的反馈了。我的控制器!
控制器:好嘞我知道了!这就给你颗糖
那么反馈不出相同结果时呢?
Button:*(呜呜呜呜) - 哑巴状态
控制器:你不出声,我可给不了你糖果哦溜了溜了
其他的ControlEvent类型也是一样的。
小总结一下
众所周知,当触摸事件发生的时候,事件的传递链是自上而下,遍历控件、点找到了这个button。
而UIButton被点击响应的背后,touch方法群体正在辛勤的工作。通过touch方法执行的结果的反馈。来判断当前Button是否被响应!
这里就简而要之的讲一讲,不足之处往后改进!