實(shí)現(xiàn)全屏滑動(dòng),解決UIScrollerView的沖突
之前我們追求 讓你三行代碼, 今天我們追求讓你隨便寫(xiě)代碼,
喜歡單手操作的我在這里我要隆重地贊美一下,今日頭條,簡(jiǎn)書(shū)APP ,我喜歡他們的原因就是他們完美實(shí)現(xiàn)了全屏滑動(dòng),不像有些APP 還要點(diǎn)左上角或者屏幕邊緣才能返回,這不符合單身20多年的我的習(xí)慣!
裝逼結(jié)束,下面是正文:
今天我們要實(shí)現(xiàn)的是不需要寫(xiě)一行代碼,實(shí)現(xiàn)全屏滑動(dòng),并且解決UIScrollerView的沖突
先看下效果

最后一個(gè)界面就是不要全屏滑動(dòng)的界面
創(chuàng)建一個(gè) UINavigationController的分類,在分類中操作
基礎(chǔ)知識(shí)
打印
NSLog(@"---------%@",self.navigationController.interactivePopGestureRecognizer);
得到的結(jié)果如下
<UIScreenEdgePanGestureRecognizer: 0x7f9ee0c3b5a0;
state = Possible;
delaysTouchesBegan = YES;
view = <UILayoutContainerView 0x7f9ee0c38170>;
target= <(action=handleNavigationTransition:
target=<_UINavigationInteractiveTransition 0x7f9ee0c3b460>)>>
系統(tǒng)管理全屏滑動(dòng)的類是 UIScreenEdgePanGestureRecognizer 這個(gè)類
執(zhí)行者是 _UINavigationInteractiveTransition == self.interactivePopGestureRecognizer.delegate
方法是 handleNavigationTransition
知道上面的思路我們需要做的就是 用我們自己的手勢(shì)去攔截系統(tǒng)的手勢(shì),然后去實(shí)現(xiàn)系統(tǒng)全屏滑動(dòng)的效果 方法: <handleNavigationTransition>
首先我們自定義手勢(shì) popPanGestureRecognizer
他的taget 和action 還是系統(tǒng)的方法,但是 手勢(shì)的delegate 換成 self 就是導(dǎo)航欄控制器
然后通過(guò) runtime hook 在viewWillAppear 的方法中 將自己創(chuàng)建的手勢(shì)添加到 self.view 就是導(dǎo)航欄控制器
接下來(lái)需要處理手勢(shì)
首先需要設(shè)置
///是否允許接收手指的觸摸點(diǎn)
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
return self.childViewControllers.count > 1; // 只有非跟控制器才需要觸發(fā)手勢(shì)
}
在跟控制器中不響應(yīng)
同時(shí)還需要寫(xiě)下面的方法,處理手勢(shì)沖突
/// 只有當(dāng)系統(tǒng)側(cè)滑手勢(shì)失敗了,才去觸發(fā)ScrollView的滑動(dòng) 這個(gè)方法返回YES,第一個(gè)和第二個(gè)互斥時(shí),第二個(gè)會(huì)失效
/**
第一個(gè)手勢(shì)是 <UIPanGestureRecognizer: 0x7fdd5d70ac90; state = Possible; view = <UILayoutContainerView 0x7fdd5d50ff20>; target= <(action=handleNavigationTransition:, target=<_UINavigationInteractiveTransition 0x7fdd5d40fd60>)>>
第二個(gè)手勢(shì)是 <UIScrollViewPanGestureRecognizer: 0x7fdd5d425840; state = Possible; delaysTouchesEnded = NO; view = <UIScrollView 0x7fdd5d8ec000>; target= <(action=handlePan:, target=<UIScrollView 0x7fdd5d8ec000>)>>
*/
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}
處理完手勢(shì)沖突后 需要處理 手勢(shì)的作用范圍,代碼如下:
///開(kāi)始進(jìn)行手勢(shì)識(shí)別時(shí)調(diào)用的方法是否接收一個(gè)手勢(shì)觸摸事件默認(rèn)為YES返回NO為不接收用處:可以在控件指定的位置使用手勢(shì)識(shí)別
- (BOOL)gestureRecognizerShouldBegin:(UIPanGestureRecognizer *)gestureRecognizer
{
if ([[self valueForKey:@"_isTransitioning"] boolValue])
{
return NO;
}
if ([self.navigationController.transitionCoordinator isAnimated])
{
return NO;
}
if (self.childViewControllers.count <= 1)
{
return NO;
}
BOOL res = NO;
if (self.isEnabled == YES)
{
// 側(cè)滑手勢(shì)觸發(fā)位置
CGPoint location = [gestureRecognizer locationInView:self.view];
CGPoint offSet = [gestureRecognizer translationInView:gestureRecognizer.view];
BOOL ret = (0 < offSet.x && location.x <= self.recognizerLength);
return ret;
}
return res;
}
如果你需要定制 在viewdidload方法中寫(xiě)下面的屬性
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
這個(gè)屬性控制著 左邊滑動(dòng)手勢(shì)的區(qū)域
self.navigationController.recognizerLength = 100;
});
除此之外
還可以設(shè)計(jì)成某一個(gè)界面不想要全屏滑動(dòng)的設(shè)計(jì)
給viewcontroller 添加一個(gè)分類 同時(shí)綁定一個(gè)屬性控制可用與否
具體代碼如下:
分別在 viewWillAppear 和 viewWillDisappear 對(duì)方法進(jìn)行交換 和賦值
-(void)_vcViewWillAppear:(BOOL)animated
{
[self _vcViewWillAppear:animated];
if (self.noPopAction)
{
self.navigationController.popPanGestureRecognizer.enabled = NO;
}
}
-(void)_vcViewWillDisAppear:(BOOL)animated
{
[self _vcViewWillDisAppear:animated];
if (self.noPopAction)
{
self.navigationController.popPanGestureRecognizer.enabled = YES;
}
}
實(shí)際使用的過(guò)程中中在 適當(dāng)位置寫(xiě)上下面的代碼就ok
self.noPopAction = YES; // 這個(gè)界面不想要全屏手勢(shì)了
到此不需要寫(xiě)一行代碼就可以搞定全屏滑動(dòng),并且也不影響你自己的 UISCrollerView的手勢(shì)
同學(xué)們?nèi)绻惺裁唇ㄗh反饋請(qǐng) 簡(jiǎn)書(shū)上聯(lián)系我
http://www.itdecent.cn/u/874b526fa570
同學(xué)們也別忘了支持一下我寫(xiě)的多張照片照片選擇框架
https://github.com/wangjinshan/IJSPhotoSDK
本篇文檔的內(nèi)容將放到
https://github.com/wangjinshan/IJSPhotoSDK 目錄下 IJSNavigationBack 文件夾下 需要的小伙伴 直接下載這個(gè)文件 然后放到自己的項(xiàng)目中可以了,不需要寫(xiě)代碼