一醋火、需求背景
現(xiàn)在很多應(yīng)用都有類似下圖這種UI
父視圖是圖中藍(lán)色框大小,中間按鈕凸起部分在視圖外潜圃,在這種情況下如果我們不做任何處理伶丐,點(diǎn)擊圖中紅色區(qū)域是無法被響應(yīng)的坐慰。
二渗柿、介紹
響應(yīng)鏈在這里就不過多介紹了兆旬,我們主要介紹事件分發(fā)時(shí)是如何找到最合適的事件處理者。
這里需要了解兩個(gè)方法:
// 判斷點(diǎn)擊區(qū)域是否在當(dāng)前視圖范圍內(nèi)
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
// 最適合處理事件的View
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
方法一用于判斷點(diǎn)擊區(qū)域是否在當(dāng)前視圖范圍內(nèi)
方法二用于尋找最適合的View
我們以上圖的例子進(jìn)行說明隧出,暫時(shí)稱呼它為tabbar踏志,其視圖范圍為圖中1區(qū)域,中間凸起部分button在視圖外的部分為2區(qū)域胀瞪,兩者重合部分為3區(qū)域针余。
在點(diǎn)擊1、2凄诞、3區(qū)域時(shí)都會先調(diào)用tabbar的- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
圆雁,只不過返回值不同,結(jié)果不同帆谍,我們詳細(xì)來看看會發(fā)生什么伪朽。
1.1、點(diǎn)擊區(qū)域1
tabbar的方法一返回YES汛蝙,接著會去遍歷tabbar上所有子控件并調(diào)用子控件中的方法一烈涮,也就是會調(diào)用button的方法一,由于button不在1區(qū)域內(nèi)窖剑,所以button的方法一返回NO坚洽,并且button的方法二返回null,然后調(diào)用tabbar的方法二并返回self即tabbar本身處理點(diǎn)擊事件西土。
1.2讶舰、點(diǎn)擊區(qū)域2
tabbar的方法一返回YES,接著會去遍歷tabbar上所有子控件并調(diào)用子控件中的方法一,也就是會調(diào)用button的方法一绘雁,所以button的方法一返回YES,并且button的方法二返回本身援所,然后調(diào)用tabbar的方法二并返回button庐舟,最終由button處理點(diǎn)擊事件。
1.3住拭、點(diǎn)擊區(qū)域3
我們在自定義tabbar時(shí)挪略,一般有兩種方式:
1、將自定義的tabbar添加到原來的tabbar上滔岳。
2杠娱、利用KVC替換掉原來的tabbar。
方式一
事件分發(fā)是由下往上進(jìn)行分發(fā)谱煤,在調(diào)用系統(tǒng)tabbar方法一的時(shí)候摊求,返回值為NO,事件不會繼續(xù)向上分發(fā)刘离,即不會調(diào)用自定義的tabbar的那兩個(gè)方法室叉,由系統(tǒng)的tabbar成為事件的接收者。此時(shí)無法實(shí)現(xiàn)我們的需求硫惕。
方式二
我們知道最終的接收者實(shí)際上是通過tabbar的方法二的返回值決定的茧痕,所以我們只需要修改自定義tabbar的方法二的實(shí)現(xiàn)即可。
// 其中self.plusButton為中間凸起按鈕
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
CGPoint newPoint = [self convertPoint:point toView:self.plusButton];
// 判斷是否屬于按鈕范圍
if ([self.plusButton pointInside:newPoint withEvent:event]) {
return self.plusButton;
} else {
return [super hitTest:point withEvent:event];
}
}
三恼除、總結(jié)
在做類似這種UI時(shí)踪旷,需要將自定義tabbar通過KVC替換掉原有tabbar,并重寫- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
返回合適的View去處理事件豁辉。