一、backBarItem和 leftBarItem 傻傻分不清楚
關(guān)于系統(tǒng)的導(dǎo)航條里backBarItem和leftBarItem有什么區(qū)別,我看了 LonlyCat 的 iOS 側(cè)滑返回手勢(shì),寫得還算比較清楚。 自己學(xué)習(xí)了以后做了個(gè)總結(jié),Demo 的內(nèi)容覆蓋還有全局側(cè)滑框架FDFullscreenPopGesture的源碼中文詳解和自己項(xiàng)目中需求對(duì)源碼的理解,框架本身代碼量也比較少,如果覺得看得吃力可以參考我的 Demo。
1. backBarItem 和 leftBarItem,交互動(dòng)畫區(qū)別:

有留意過微信的返回手勢(shì)效果嗎? 微信的返回手勢(shì)就是第一種,覆蓋了 leftBackItem,手勢(shì)返回的過程中,左上角的文字是漸暗的。
第二種效果就是 backBarItem 了,也是系統(tǒng)默認(rèn)的效果,會(huì)慢慢遠(yuǎn)離返回按鈕,然后 pop。
2. backBarItem 和 leftBarItem,代碼區(qū)別,假如 A要 push B, A --> B
- leftBarItem:
在 B 控制器中實(shí)現(xiàn)如下代碼,就可以覆蓋 leftBarItem
UIButton *lefuButton = [UIButton buttonWithType:UIButtonTypeCustom];
lefuButton.titleLabel.font = [UIFont systemFontOfSize:17];
[lefuButton setImage:[UIImage imageNamed:@"nav_back"] forState:UIControlStateNormal];
[lefuButton setImage:[UIImage imageNamed:@"nav_back"] forState:UIControlStateHighlighted];
[lefuButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[lefuButton setTitleColor:[UIColor whiteColor] forState:UIControlStateHighlighted];
[lefuButton setImageEdgeInsets:UIEdgeInsetsMake(0, -10, 0, 0)];
[lefuButton setTitle:@"leftBarItem" forState:UIControlStateNormal] ;
[lefuButton sizeToFit];
[lefuButton addTarget:self action:@selector(back) forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem *leftButtonItem = [[UIBarButtonItem alloc] initWithCustomView:lefuButton];
self.navigationItem.leftBarButtonItem = leftButtonItem;
- backBarItem:
在 A(注意這里不是 B) 控制器中實(shí)現(xiàn)如下代碼,就可以覆蓋 backBarItem
UIBarButtonItem *backItem = [[UIBarButtonItem alloc]init];
backItem.title = @"backBarItem";
//如果使用了自己的返回圖片, 需要適當(dāng)調(diào)整文字和圖片的距離
[backItem setBackButtonTitlePositionAdjustment:UIOffsetMake(8, 0) forBarMetrics:UIBarMetricsDefault];
[self.navigationController.navigationBar setTintColor:[UIColor blackColor]];
self.navigationItem.backBarButtonItem = backItem;
如果僅僅在 A 控制器中覆蓋 backBarButtonItem 的話,那 B 控制器中的返回圖片還是系統(tǒng)的, 如果想要替換成自己的返回圖片,就要在導(dǎo)航控制器中添加如下代碼,替換系統(tǒng)的backIndicatorImage
UIImage *backImg = [UIImage imageNamed:@"nav_back"];
backImg = [backImg imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
self.navigationBar.backIndicatorImage = backImg;
self.navigationBar.backIndicatorTransitionMaskImage = backImg;
3. backBarItem 和leftBarItem , 在項(xiàng)目應(yīng)用中的區(qū)別:
- 覆蓋leftBarItem
系統(tǒng)自帶的邊緣側(cè)滑手勢(shì)會(huì)失效,需要重新在導(dǎo)航控制器中設(shè)置邊緣返回手勢(shì)的代理為某個(gè)對(duì)象,可以在代理中處理邊緣側(cè)滑手勢(shì)
self.interactivePopGestureRecognizer.delegate = someObject;
優(yōu)點(diǎn)當(dāng)然是可以更靈活的處理 leftBarItem的點(diǎn)擊事件和 UI 方面;
- 覆蓋backBarItem
系統(tǒng)自帶的邊緣側(cè)滑手勢(shì)會(huì)不會(huì)失效,但是想要靈活的處理 backBarItem 的事件那就不行了。
二、關(guān)于FDFullscreenPopGesture
這個(gè) sunny 開源的框架,解決了無論是覆蓋 leftBarItem 還是 backBarItem 的返回手勢(shì)問題, 并且把邊緣返回手勢(shì),改變成了全局返回手勢(shì),同時(shí)解決了控制器之間存在導(dǎo)航條是透明的情況,不同控制器之間的無縫銜接。
整個(gè)框架運(yùn)用分類 + runtime 的寫完,不用寫一行代碼就可以實(shí)現(xiàn)全局返回手勢(shì),因?yàn)?runtime 會(huì)調(diào)用分類的+load 方法,而且是后于類和子類調(diào)用??蚣苄Ч麍D如下:

但是在實(shí)際開發(fā)中我的項(xiàng)目在導(dǎo)航條需要隱藏的控制器中,往下滑動(dòng)時(shí)候,導(dǎo)航條還需要漸變,因?yàn)镕DFullscreenPopGesture 是通過
self.fd_prefersNavigationBarHidden = YES;
這個(gè)控制器的屬性來隱藏導(dǎo)航條的,如果再在導(dǎo)航條上加上透明度漸變的效果,那來回 pop,push 其他控制器的時(shí)候根本無法好好處理導(dǎo)航條的隱藏和顯示,所以我在 demo 中,在需要漸變導(dǎo)航條的控制器中添加了一個(gè)假的導(dǎo)航條,這是一個(gè)很好的解決方式。

附上Demo, Demo 中附有FDFullscreenPopGesture源碼中文詳解,因?yàn)樵创a為了簡(jiǎn)潔和方便,把所有分類都放到一個(gè)文件中,我為了能讓其更簡(jiǎn)單易懂,就把各個(gè)分類文件能分開就分開了, 雖然文件多了但是結(jié)構(gòu)更加清晰。