右滑手勢(shì)返回##
原文
ios7開(kāi)始 蘋果增加了頁(yè)面 右滑返回的效果;具體的是以UINavigationController為容器的ViewController間右滑切換頁(yè)面词顾。
代碼里的設(shè)置是:
self.navigationController.interactivePopGestureRecognizer.enabled = YES;(default is YES)
可以看到蘋果給navigationController添加了一個(gè)手勢(shì)(具體為UIScreenEdgePanGestureRecognizer(邊緣手勢(shì),同樣是ios7以后才有的))咒循,就是利用這個(gè)手勢(shì)實(shí)現(xiàn)的 ios7的側(cè)滑返回隅茎。
問(wèn)題1:然而事情并非我們想的那么簡(jiǎn)單欣孤。
1.當(dāng)我們用系統(tǒng)的UINavigationController,并且也是利用系統(tǒng)的navigateBar的時(shí)候呀潭,是完全沒(méi)有問(wèn)題的
2.但是當(dāng)我們沒(méi)有用系統(tǒng)的navigateBar或者自定義了返回按鈕的時(shí)候钉迷,這個(gè)時(shí)候 右滑返回是失效的。
解決(問(wèn)題1)辦法:對(duì)于這種失效的情況钠署,考慮到interactivePopGestureRecognizer也有delegate屬性糠聪,替換默認(rèn)的self.navigationController.interactivePopGestureRecognizer.delegate來(lái)配置右滑返回的表現(xiàn)也是可行的。
我們可以在主NavigationController中設(shè)置一下:
self.navigationController.interactivePopGestureRecognizer.delegate =(id)self
問(wèn)題2:
但是出現(xiàn)很多問(wèn)題踏幻,比如說(shuō)在rootViewController的時(shí)候這個(gè)手勢(shì)也可以響應(yīng)枷颊,導(dǎo)致整個(gè)程序頁(yè)面不響應(yīng);push了多層后该面,快速的觸發(fā)兩次手勢(shì)夭苗,也會(huì)錯(cuò)亂
解決(問(wèn)題2)辦法:
@interface NavRootViewController : UINavigationController
@property(nonatomic,weak) UIViewController* currentShowVC;
@end
@implementation NavRootViewController
-(id)initWithRootViewController:(UIViewController *)rootViewController
{
NavRootViewController* nvc = [super initWithRootViewController:rootViewController];
self.interactivePopGestureRecognizer.delegate = self;
nvc.delegate = self;
return nvc;
}
-(void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated{
}
-(void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated{
if (navigationController.viewControllers.count == 1)
self.currentShowVC = Nil;
else
self.currentShowVC = viewController;
}
-(BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{
if (gestureRecognizer == self.interactivePopGestureRecognizer) {
return (self.currentShowVC == self.topViewController); //the most important
}
return YES;
}
@end
問(wèn)題三:
UIScrollView上手勢(shì)失靈:經(jīng)研究,發(fā)現(xiàn)是UIScrollView上已經(jīng)添加了 panGestureRecognizer(滑動(dòng))手勢(shì)
【解決方案】
蘋果以UIGestureRecognizerDelegate的形式隔缀,支持多個(gè)UIGestureRecognizer共存题造。其中的一個(gè)方法是:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer;
一句話總結(jié)就是此方法返回YES時(shí),手勢(shì)事件會(huì)一直往下傳遞猾瘸,不論當(dāng)前層次是否對(duì)該事件進(jìn)行響應(yīng)界赔。
@implementation UIScrollView (AllowPanGestureEventPass)
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{
if ([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]] && [otherGestureRecognizer isKindOfClass:[UIScreenEdgePanGestureRecognizer class]]){
return YES;
}else {
return NO;
}
}
這種方式就是建一個(gè)UISCrollVIew的category,然后我用的時(shí)候是全局用的牵触,不知道為什么在快速返回上一層的時(shí)候并快速點(diǎn)擊會(huì)照成線程卡死淮悼。 還有就是兩個(gè)手勢(shì)共存,所以在返回上一層的過(guò)程中揽思,UIScrollerView還會(huì)滾動(dòng)
事實(shí)上袜腥,對(duì)UIGestureRecognizer來(lái)說(shuō),它們對(duì)事件的接收順序和對(duì)事件的響應(yīng)是可以分開(kāi)設(shè)置的钉汗,即存在接收鏈和響應(yīng)鏈羹令。接收鏈如上文所述,和UIView綁定损痰,由UIView的層次決定接收順序福侈。
而響應(yīng)鏈在apple君的定義下,邏輯出奇的簡(jiǎn)單卢未,只有一個(gè)方法可以設(shè)置多個(gè)gestureRecognizer的響應(yīng)關(guān)系:
- (void)requireGestureRecognizerToFail:(UIGestureRecognizer *)otherGestureRecognizer;
//從UINavigationController里得到這個(gè)邊緣手勢(shì)
@implementation UINavigationController (iOS7Support)
@dynamic screenEdgePanGestureRecognizer;
- (UIScreenEdgePanGestureRecognizer *)screenEdgePanGestureRecognizer{
UIScreenEdgePanGestureRecognizer *screenEdgePanGestureRecognizer = nil;
if (self.view.gestureRecognizers.count > 0){
for (UIGestureRecognizer *recognizer in self.view.gestureRecognizers){
if ([recognizer isKindOfClass:[UIScreenEdgePanGestureRecognizer class]]){
screenEdgePanGestureRecognizer = (UIScreenEdgePanGestureRecognizer *)recognizer;
break;
}
}
}
return screenEdgePanGestureRecognizer;
}
@end
//當(dāng)screenEdgePanGestureRecognizer生效時(shí)肪凛,UIScrollerView的panGestureRecognizer失效堰汉,這樣就解決了沖突
UIScreenEdgePanGestureRecognizer *screenEdgePanGestureRecognizer = self.navigationController.screenEdgePanGestureRecognizer;
[_scrollerView.panGestureRecognizer requireGestureRecognizerToFail:screenEdgePanGestureRecognizer];
全屏的右滑返回##
FDFullscreenPopGesture這個(gè)開(kāi)源項(xiàng)目里用運(yùn)行時(shí)很簡(jiǎn)單的實(shí)現(xiàn)了全屏的右滑返回。
有人說(shuō)直接用下面這種kvo的方式就能實(shí)現(xiàn)了显拜,這是系統(tǒng)原有的私有屬性衡奥,增大那個(gè)響應(yīng)區(qū)域就可以了。但我自己還沒(méi)實(shí)測(cè)過(guò)远荠,有興趣的可以試試矮固。
[self.interactivePopGestureRecognizer setValue:@([UIScreen mainScreen].bounds.size.width) forKeyPath:@"_recognizer._settings._edgeSettings._edgeRegionSize"];
touchesbegan未響應(yīng)##
touchesbegan跟UITapGestureRecognizer同時(shí)存在時(shí),tap會(huì)有一個(gè)屬性是cancelsTouchesInView譬淳,默認(rèn)為YES档址,設(shè)置為NO就可以使touchesbegan響應(yīng)了。
參考:一個(gè)Bug引發(fā)的對(duì)UIGestureRecognizer的思考