一天打漁,三天曬網。大家猴又是我,堅持在工作日中的一日一博客。
今天聊的是有關上幾篇文章提到的<事件響應鏈>的后續。在點擊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是否被響應!
這里就簡而要之的講一講,不足之處往后改進!