1. 程式人生 > >更改系統預設導航欄的返回按鈕

更改系統預設導航欄的返回按鈕

前言

今天我們來重點討論導航欄返回的問題,包括各種問題的解決方案。

系統預設導航欄的返回按鈕和返回方式

在預設情況下,導航欄返回按鈕長這個樣子

導航欄預設返回按鈕

導航欄右上角的返回按鈕,其文字預設為上一個ViewController的標題,如果上一個ViewController沒有標題,則為Back(中文環境下為“返回”)。

在預設情況下,導航欄返回的點選互動和滑動互動如下

預設導航欄互動

這些東西不需要任何設定和操作,因此也沒有其他需要說明的地方。

自定義左上角的返回按鈕

絕大多數情況下,我們都需要根據產品需求自定義左上角的返回按鈕,雖然這對大多數開發者來說不是什麼難事,但依然有幾個問題值得注意。

替換左上角返回按鈕

替換返回按鈕非常簡單,只需要在ViewController中建立一個UIBarButtonItem和一張圖片,併為按鈕新增相應的點選事件即可,程式碼如下

- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.

UIButton * leftBtn = [UIButton buttonWithType:UIButtonTypeSystem];
leftBtn.frame = CGRectMake(0, 0, 25,25);
[leftBtn setBackgroundImage:[UIImage imageNamed:@"nav_back"] forState:UIControlStateNormal];
[leftBtn addTarget:self action:@selector(leftBarBtnClicked:) forControlEvents:UIControlEventTouchUpInside];
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc]initWithCustomView:leftBtn];
}
- (void)leftBarBtnClicked:(UIButton *)btn
{
 [self.navigationController popViewControllerAnimated:YES];
}

我們來看一眼效果

替換返回按鈕

調整按鈕位置

我們可以看到,上面的按鈕是有點偏左的,那如果我們想調整按鈕的位置該怎麼做呢?設定Frame顯然是行不通的,因為導航欄的NavigationItem是個比較特殊的View,我們無法通過簡單的調整Frame來的調整左右按鈕的位置。但是在蘋果提供的 UIButtonBarItem 中有個叫做 UIBarButtonSystemItemFixedSpace 的控制元件,利用它,我們就可以輕鬆調整返回按鈕的位置。具體使用方法如下

//建立返回按鈕
UIButton * leftBtn = [UIButton buttonWithType:UIButtonTypeSystem];
leftBtn.frame = CGRectMake(0, 0, 25,25);
[leftBtn setBackgroundImage:[UIImage imageNamed:@"icon_back"] forState:UIControlStateNormal];
[leftBtn addTarget:self action:@selector(leftBarBtnClicked:) forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem * leftBarBtn = [[UIBarButtonItem alloc]initWithCustomView:leftBtn];;
//建立UIBarButtonSystemItemFixedSpace
UIBarButtonItem * spaceItem = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil];
//將寬度設為負值
spaceItem.width = -15;
//將兩個BarButtonItem都返回給NavigationItem
self.navigationItem.leftBarButtonItems = @[spaceItem,leftBarBtn];

我們來看一眼效果

調整返回按鈕位置

可以看到,我們的返回按鈕已經緊靠著螢幕邊緣。

這個方法同樣適用於調整導航欄右側的按鈕

讓滑動返回手勢生效

如果使用自定義的按鈕去替換系統預設返回按鈕,會出現滑動返回手勢失效的情況。解決方法也很簡單,只需要重新新增導航欄的 interactivePopGestureRecognizer 的 delegate 即可。

首先為ViewContoller新增 UIGestureRecognizerDelegate 協議

然後設定代理

self.navigationController.interactivePopGestureRecognizer.delegate = self;

至此,我們已經將返回按鈕替換為我們的自定義按鈕,並使滑動返回重新生效。接下來,我們繼續來解決互動上的問題。

全屏滑動返回

這個一個很常見的需求,網上解決方案也很多,這裡將本人常用的方法貼到這裡。僅供參考

實現全屏滑動返回僅需在導航欄給導航欄新增 UIGestureRecognizerDelegate 協議,並在ViewDidLoad中寫入如下程式碼

// 獲取系統自帶滑動手勢的target物件
id target = self.interactivePopGestureRecognizer.delegate;

// 建立全屏滑動手勢,呼叫系統自帶滑動手勢的target的action方法
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:target action:@selector(handleNavigationTransition:)];

// 設定手勢代理,攔截手勢觸發
pan.delegate = self;

// 給導航控制器的view新增全屏滑動手勢
[self.view addGestureRecognizer:pan];

// 禁止使用系統自帶的滑動手勢
self.interactivePopGestureRecognizer.enabled = NO;

我們來看一眼效果(注意滑鼠位置)

全屏滑動返回.gif

成功

這種方法的原理其實很簡單,其實就是自定義一個全屏滑動手勢,並將滑動事件設定為系統滑動事件,然後禁用系統滑動手勢即可。 handleNavigationTransition 就是系統滑動的方法,雖然系統並未提供介面,但是我們我們可以通過runtime找到這個方法,因此直接呼叫即可。兩位,不必擔心什麼私有API之類的問題,蘋果如果按照方法名去判斷是否使用私有API,那得誤傷多少App。