IOS 11之前可以通過 navigationItem.leftBarButtonItem.width來控制按鈕的偏移,但是IOS 11之后這個設(shè)置不生效了,添加leftBarButtonItem后的默認(rèn)狀態(tài)如下:

網(wǎng)上有兩種主流的解決方案:
第一種是運(yùn)用運(yùn)行時+擴(kuò)展分類的方式來擴(kuò)大leftBarButtonItem的點(diǎn)擊區(qū)域,使得UINavigationBar左右兩邊那20像素也能成為UIBarButtonItem點(diǎn)擊區(qū)域,同時設(shè)置button的imageEdgeInsets使圖片向左偏移至button外,這種不走尋常路的方法總感覺乖乖的,而且代碼繁多,擴(kuò)展了3個分類,與我自己的UINavigationItem分類也有沖突,所以我不會使用。
第二種是通過觀察xCode - Debug View Hierarchy,找到UINavigationItem 在IOS11中的層級結(jié)構(gòu),精準(zhǔn)地找到位置偏移的View,然后在視圖控制器的viewDidLayoutSubviews中重新設(shè)置這個View的Frame。

//重新指定IOS11中有偏移的View的位置
- (void)viewDidLayoutSubviews{
if ([[[UIDevice currentDevice]systemVersion]floatValue] < 11.0) return;
UINavigationItem * item=self.navigationItem;
NSArray * array=item.leftBarButtonItems;
if (array&&array.count!=0){
UIBarButtonItem * buttonItem=array[0];
UIView * view =[[[buttonItem.customView superview] superview] superview];
NSArray * arrayConstraint=view.constraints;
for (NSLayoutConstraint * constant in arrayConstraint) {
if (fabs(constant.constant) > 10) {
constant.constant=0;
}
}
}
}
但是這樣會有風(fēng)險
首先,這種方法在IOS 11.2之后會出現(xiàn)抖動的現(xiàn)象,其次,在往后的新IOS系統(tǒng)中,UINavigationItem的層級可能又會有新的變化,所以這樣做是不靠譜的,于是我想綜合這兩種方法去找到一種更加簡潔的、能更好地向后兼容的解決方案,折騰了幾個小時候后,無論我怎么做都不完美,于是我開始思考這個leftBarButtonItem和backBarButtonItem的區(qū)別,蘋果為什么會將兩個極為相似的東西放在同一個地方,后來我明白了,其實(shí)leftBarButtonItem和rightBarButtonItem的意義一樣,只是一個簡單的功能按鈕,并不能代替“返回”按鈕,你想想,你通常在導(dǎo)航欄后邊添加一個“保存”或“更多”按鈕時是不是不需要貼邊呢,反而貼邊才奇怪呢,而導(dǎo)航欄左邊的功能按鈕(leftBarButtonItem)同右邊的功能按鈕(rightBarButtonItem)意義是一樣的,使用場景應(yīng)該是:當(dāng)使用present方式彈出控制器時是沒有返回按鈕存在的,此時可以在導(dǎo)航欄上添加左、右功能按鈕,想到這里,我才茅塞頓開恍然大悟,原來我們一直通過設(shè)置leftBarButtonItem來自定義返回按鈕才是錯誤的方向,因?yàn)樵O(shè)置leftBarButtonItem后,系統(tǒng)自帶的右滑返回上一個控制器的手勢也隨之消失,我們還得自己添加一個右滑手勢,這是一條彎路啊。所以,我們?yōu)楹尾蛔呓輳侥兀?若是只想單純的自定義導(dǎo)航欄返回按鈕,應(yīng)該從backBarButtonItem上下手。
解決方案:
/**
設(shè)置返回按鈕:自定義圖片+無文字顯示, 由首個控制器設(shè)置
@param backIndicatorImage 自定義圖片
@param backIndicatorTransitionMaskImage 轉(zhuǎn)場遮罩圖片
*/
- (void)setupBackBarButtonItemWithImage:(UIImage *)backIndicatorImage backIndicatorTransitionMaskImage:(UIImage *)backIndicatorTransitionMaskImage tintColor:(UIColor *)tintColor {
UIBarButtonItem *backItem = [[UIBarButtonItem alloc]initWithTitle:nil style:UIBarButtonItemStylePlain target:nil action:nil];
self.navigationController.navigationBar.tintColor = tintColor;
self.navigationController.navigationBar.backIndicatorImage = backIndicatorImage;
self.navigationController.navigationBar.backIndicatorTransitionMaskImage = backIndicatorTransitionMaskImage;
self.navigationItem.backBarButtonItem = backItem;
}
如此一來,系統(tǒng)自帶的右滑返回手勢不會消失,右滑的過程中導(dǎo)航欄的預(yù)設(shè)動畫也還在,網(wǎng)上非常火的“FDFullscreenPopGesture”也就沒有了用武之地。
完。