1磷账、先來說一下概念性的東西
Hit-Test 是什么
Hit-Test 是一個決定一個點(比如一個觸摸點)是否落在一個給定的物理對象上(比如繪制在屏幕上的UIView)的一個過程。
Hit-Test執(zhí)行時機
Hit-Test是在每次手指觸摸時執(zhí)行的跟磨。并且是在任何視圖或者手勢收到UIEvent(代表觸摸屬于的事件)之前杆怕。
Hit-Test 的實現(xiàn)
實現(xiàn):Hit-Test采用深度優(yōu)先的反序訪問迭代算法(先訪問根節(jié)點然后從高到低訪(從離用戶近的視圖或者說是后添加的視圖為低節(jié)點)族购。這種遍歷方法可以減少遍歷迭代的次數(shù)壳贪。
結(jié)束條件:一旦找到最深的包含觸摸點的后裔視圖就停止遍歷(注意,是最深的)寝杖。
2违施、覆蓋hitTest:withEvent:的一些用途
1. 增加視圖的觸摸區(qū)域
按鈕太小,優(yōu)雅的自定義UIButton瑟幕,覆蓋hitTest:withEvent:方法
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
if (!self.isUserInteractionEnabled || self.isHidden || self.alpha <= 0.01) {
return nil;
}
CGRect touchRect = CGRectInset(self.bounds, -10, -10);
if (CGRectContainsPoint(touchRect, point)) {
for (UIView *subview in [self.subviews reverseObjectEnumerator]) {
CGPoint convertedPoint = [subview convertPoint:point fromView:self];
UIView *hitTestView = [subview hitTest:convertedPoint withEvent:event];
if (hitTestView) {
return hitTestView;
}
}
return self;
}
return nil;
}
2. 傳遞觸摸事件給父視圖
有的時候?qū)τ谝粋€視圖忽略觸摸事件并傳遞給下面的視圖是很重要的磕蒲。例如,假設(shè)一個透明的視圖覆蓋在應(yīng)用內(nèi)所有視圖的最上面只盹。覆蓋層有子視圖應(yīng)該相應(yīng)觸摸事件的一些控件和按鈕辣往。但是觸摸覆蓋層的其他區(qū)域應(yīng)該傳遞給覆蓋層下面的視圖。為了完成這個行為殖卑,覆蓋層需要覆蓋hitTest:withEvent:方法來返回包含觸摸點的子視圖中的一個站削,然后其他情況返回nil,包括覆蓋層包含觸摸點的情況:
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
UIView *hitTestView = [super hitTest:point withEvent:event];
if (hitTestView == self) {
hitTestView = nil;
}
return hitTestView;
}
3. 傳遞觸摸事件給子視圖
一個圖片瀏覽器孵稽,在方框內(nèi)滑動许起,可以翻動圖片,但是在方框之外是無法響應(yīng)的菩鲜,因為手指落點不在圖片瀏覽器的bounces里面园细,那么如何讓手指落在上圖位置時,也可以滾動圖片呢睦袖?方法是在圖片瀏覽器的父視圖中珊肃,重載hitTest:withEvent:方法荣刑,當(dāng)觸摸到圖片瀏覽器自視圖之外的視圖時馅笙,返回圖片瀏覽器即可:
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
UIView *hitTestView = [super hitTest:point withEvent:event];
if (hitTestView) {
hitTestView = self.scrollView;
}
return hitTestView;
}
4. 響應(yīng)子view超出了父view的bounds事件
比如自定義Tabbar中間的大按鈕,點擊超出Tabbar bounds的區(qū)域也需要響應(yīng)厉亏,此時重載父view的hitTest: withEvent:方法董习,去掉點擊必須在父view內(nèi)的判斷,然后子view就能成為 hit-test view用于響應(yīng)事件:
最后這個案例引用的0o凍僵的企鵝o0 的UITabBar 自定義中間大按鈕