IOS —— UIButton被点击响应的背后

一天打渔,三天晒网。大家猴又是我,坚持在工作日中的一日一博客。

今天聊的是有关上几篇文章提到的<事件响应链>的后续。在点击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是否被响应

这里就简而要之的讲一讲,不足之处往后改进!

posted @ 2018-12-14 01:45  幽幽幽瓜  阅读(1354)  评论(0编辑  收藏  举报