轉(zhuǎn)載鏈接:
https://blog.csdn.net/mingC0758/article/details/110508615
UIButton、UIGestureRecognizer和hitTest
概述
父視圖是一個(gè)普通的UIView,添加了點(diǎn)擊手勢(shì)UITapGestureRecognizer;
UIButton可以點(diǎn)擊
UIView的userInteractionEnable = YES(默認(rèn)值),無手勢(shì)
UIBotton和UIView都是GeastureContainerView的子View
需求
當(dāng)點(diǎn)擊UIView時(shí),既不響應(yīng)UIButton,也不響應(yīng)GestureContainerView。
現(xiàn)狀
在沒有任何處理的情況下,點(diǎn)擊UIButton區(qū)域,不會(huì)響應(yīng)GestureContainerView,原因是:系統(tǒng)會(huì)先調(diào)用被觸摸視圖的
gestureRecognizerShouldBegin:方法,UIButton繼承自UIControl,在點(diǎn)擊的場(chǎng)景下該方法返回NO,因此點(diǎn)擊UIButton時(shí),父視圖的點(diǎn)擊手勢(shì)不會(huì)生效。
在 [gestureRecognizerShouldBegin:] 階段首先被調(diào)用的是被觸摸視圖的 [gestureRecognizerShouldBegin:] 方法,其參數(shù)是我們的 tap gesture 。而 UIButton 的 [gestureRecognizerShouldBegin:] 實(shí)現(xiàn)中,指定對(duì)非添加在自己身上的 tap gesture ,返回 false ,即不可響應(yīng)。所以點(diǎn)擊最終響應(yīng)的是 UIButton ,其下面視圖的 tap gesture 得不到響應(yīng)。如果讀者重寫 UIButton 的 [gestureRecognizerShouldBegin:] 方法,讓其返回 true ,會(huì)發(fā)現(xiàn)點(diǎn)擊 UIButton 時(shí), UIButton 沒有響應(yīng),響應(yīng)的卻是其父視圖的 tap gesture 。這也說明了 UIGesture 比 UIControl 的優(yōu)先級(jí)更高。另外, UIButton 的 [gestureRecognizerShouldBegin:] 實(shí)現(xiàn)中沒有對(duì)其他手勢(shì)做限制,即返回的 true ,所以你在 UIButton 上雙擊、滑動(dòng)時(shí),這些手勢(shì)都能得到其父視圖的識(shí)別
當(dāng)點(diǎn)擊最上層的UIView時(shí),首先默認(rèn)的userInteractionEnable = YES,因此點(diǎn)擊時(shí)間不會(huì)透?jìng)鞯経IButton;同時(shí)也因?yàn)樗旧頉]有添加任何手勢(shì)識(shí)別器,所以GestureContainerView的UITapGestureRecognizer會(huì)被觸發(fā)(手勢(shì)識(shí)別器的優(yōu)先級(jí)最高)。
解決方案
重寫UIButton和UIView的gestureRecognizerShouldBegin方法,return NO屏蔽所有手勢(shì)。
GestureContainerView設(shè)置代理方法- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch,touch.view != GestureContainerView時(shí),return NO。
其他
userInteractionEnable和hitTest的關(guān)系
userInteraction = NO的情況下可以觸發(fā)手勢(shì)嗎?不能。
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
? ? if (!self.isUserInteractionEnabled || self.isHidden || self.alpha <= 0.01) {
? ? ? ? return nil;
? ? }
? ? if ([self pointInside:point withEvent:event]) {
? ? ? ? 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;
}