iOS 常見的手勢沖突解決方案

iOS事件傳遞及響應(yīng)鏈

第一種場景 系統(tǒng)控件和手勢的沖突

我們點(diǎn)擊UIButton,發(fā)現(xiàn)只響應(yīng)了button的點(diǎn)擊事件

如何使得UIButton的點(diǎn)擊事件和view的手勢事件同時響應(yīng)呢

可以設(shè)置tap的cancelsTouchesInView為NO,這樣Button的點(diǎn)擊事件和View的手勢事件都會響應(yīng)

// default is YES. causes touchesCancelled:withEvent: or pressesCancelled:withEvent: to be sent to the view for all touches or presses recognized as part of this gesture immediately before the action method is called.


第二種場景?UICollectionView和點(diǎn)擊手勢的沖突

點(diǎn)擊UICollectionView的cell,發(fā)現(xiàn)cell沒有被響應(yīng),響應(yīng)的是tap手勢事件

如果想要點(diǎn)擊響應(yīng)的是cell的點(diǎn)擊事件,而不是viewtap手勢,該如何實(shí)現(xiàn)呢

? ? tap.delegate = self;

實(shí)現(xiàn)gestureRecognizer:shouldReceiveTouch:代理

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch

{

?? ? // 若為UICollectionViewCell(即點(diǎn)擊了collectionViewCell),

? ? if ([touch.view isKindOfClass:[UICollectionViewCell class]]) {

? ? // cell 不需要響應(yīng) 父視圖的手勢,保證didselect 可以正常

? ? ? ? return NO;

? ? }

? ? //默認(rèn)都需要響應(yīng)

? ? return? YES;

}


第三種場景 兩個手勢間的沖突

兩個view上都加了點(diǎn)擊手勢,如果想兩個手勢都響應(yīng)

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizershouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{

? ? return YES;

}

第四種場景 兩個scrollView的滑動沖突

項(xiàng)目中常遇到一種場景,UIScrollView上增加了一個UIScrollView的子視圖,當(dāng)某些條件下需要父視圖滑動,某些情況下需要子視圖滑動

例如一個UICollectionView嵌套了一個UICollectionView,希望嵌套的UICollectionView在父視圖達(dá)到一定高度時,父視圖不再滾動,而是子視圖滾動

CustomCell內(nèi)也有一個collectionView(CustomCollectionView 類)

CustomCollectionView設(shè)置一個屬性customScrollEnable,用來控制當(dāng)與其他手勢沖突時的優(yōu)先級,CustomCollectionView類實(shí)現(xiàn)gestureRecognizer代理

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRequireFailureOfGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{

? ? if (self.customScrollEnable) {

? ? ? ? returngestureRecognizer !=self.panGestureRecognizer;

? ? }

? ? returngestureRecognizer ==self.panGestureRecognizer;

}

在父視圖的scrollViewDidScroll

子視圖的scrollViewDidScroll里

這樣就可以通過兩個很簡單的判斷設(shè)置customScrollEnable屬性控制滑動手勢的優(yōu)先級

補(bǔ)充手勢代理

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer;

手勢識別器是否能夠開始識別手勢.

當(dāng)手勢識別器識別到手勢,準(zhǔn)備從UIGestureRecognizerStatePossible狀態(tài)開始轉(zhuǎn)換時.調(diào)用此代理,如果返回YES,那么就繼續(xù)識別,如果返回NO,那么手勢識別器將會將狀態(tài)置為UIGestureRecognizerStateFailed.

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer;

gestureRecognizer : 此對象發(fā)送的代理消息.

返回YES允許gestureRecognizer與otherGestureRecognizer同時識別.

如果返回NO,分兩種情況.1.兩個手勢都返回NO,那么不會同時識別.如果一個NO,一個YES.可能會同時識別.

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRequireFailureOfGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer NS_AVAILABLE_IOS(7_0);

一般用來重寫該方法.來定義什么時候手勢識別失敗.如果直接返回YES,那么gestureRecognizer與otherGestureRecognizer互斥的話gestureRecognizer識別失敗. 可以用tap手勢和longPress手勢試試.

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer NS_AVAILABLE_IOS(7_0);

和3差不多,注意這個Be,所以是相反的,如果互斥,otherGestureRecognizer識別失敗.

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch;

返回手勢識別器是否允許檢查手勢對象.

UIKit將會在touchesBegan:withEvent:方法之前調(diào)用這個代理.

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceivePress:(UIPress *)press;

返回手勢識別器是否允許檢查按壓(UIPress對象).

UIKit將會在touchesBegan:withEvent:方法之前調(diào)用這個代理.

我們可以通過配置手勢的屬性來改變它的表現(xiàn),下面介紹三個常用的屬性:

cancelsTouchesInView:該屬性默認(rèn)是 true。顧名思義,如果設(shè)置成 false,當(dāng)手勢識別成功時,將不會發(fā)送 touchesCancelled 給目標(biāo)視圖,從而也不會打斷視圖本身方法的觸發(fā),最后的結(jié)果是手勢和本身方法同時觸發(fā)。有的時候我們不希望手勢覆蓋掉視圖本身的方法,就可以更改這個屬性來達(dá)到效果。

delaysTouchesBegan:該屬性默認(rèn)是 false。在上個例子中我們得知,在手指觸摸屏幕之后,手勢處于 .possible 狀態(tài)時,視圖的 touches 方法已經(jīng)開始觸發(fā)了,當(dāng)手勢識別成功之后,才會取消視圖的 touches 方法。當(dāng)該屬性時 true 時,視圖的 touches 方法會被延遲到手勢識別成功或者失敗之后才開始。也就是說,假如設(shè)置該屬性為 true ,在整個過程中識別手勢又是成功的話,視圖的 touches 系列方法將不會被觸發(fā)。

delaysTouchesEnded:該屬性默認(rèn)是 true。與上個屬性類似,該屬性為 true 時,視圖的 touchesEnded 將會延遲大約 0.15s 觸發(fā)。該屬性常用于連擊,比如我們需要觸發(fā)一個雙擊手勢,當(dāng)我們手指離開屏幕時應(yīng)當(dāng)觸發(fā) touchesEnded,如果這時該屬性為 false,那就不會延遲視圖的 touchesEnded 方法,將會立馬觸發(fā) ,那我們的雙擊就會被識別為兩次單擊。當(dāng)該屬性是 true 時,會延遲 touchesEnded 的觸發(fā),將兩次單擊連在一起,來正常識別這種雙擊手勢。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容