iOS 定制導(dǎo)航欄
在 App 開發(fā)的過程中,經(jīng)常會(huì)要求對(duì)頂部導(dǎo)航欄進(jìn)行自定義。本文將介紹在基于 mPaaS 框架創(chuàng)建的頁面中,自定義導(dǎo)航欄的方法。包括定制應(yīng)用主題和定制某一個(gè)頁面導(dǎo)航欄樣式。
基礎(chǔ)概念
導(dǎo)航欄元素分布
導(dǎo)航欄元素主要分布在三個(gè)區(qū)域。一般對(duì)導(dǎo)航欄的定制化需求,最終都會(huì)變?yōu)閷?duì)這幾個(gè)區(qū)域的修改:
back:返回按鈕控制區(qū)域,由 mPaaS 頁面基類創(chuàng)建,默認(rèn)樣式為返回箭頭 + 返回文案。
title/subTitle:標(biāo)題欄控制區(qū)域,默認(rèn)不顯示。若需顯示,請(qǐng)調(diào)用系統(tǒng)方法設(shè)置當(dāng)前頁面的 title。
optionMenu:頁面菜單選項(xiàng)區(qū)域,默認(rèn)不顯示。如需顯示,請(qǐng)調(diào)用系統(tǒng)方法設(shè)置當(dāng)前頁面的 rightNavigationItem。
導(dǎo)航欄結(jié)構(gòu)
如下圖所示,基于 mPaaS 框架創(chuàng)建的應(yīng)用,默認(rèn)的 UI 結(jié)構(gòu)為:
window/navigationController
>tabViewController
> 每個(gè) tab 嵌入一個(gè)viewController
。即應(yīng)用主 window 的根應(yīng)用是一個(gè)UINavigationController
的對(duì)象,UINavigationController
的根應(yīng)用是一個(gè)UITabViewController
。由以上 UI 結(jié)構(gòu)可以看出,整個(gè)應(yīng)用全局只有一個(gè)
navigationController
,因此所有頁面共用同一個(gè)導(dǎo)航欄(默認(rèn)使用APNavigationBar
創(chuàng)建)。為了統(tǒng)一所有頁面的導(dǎo)航欄樣式,要求 mPaaS 應(yīng)用中,所有頁面所在的 VC 都要繼承
DTViewControler
,包括 native 和 H5 頁面。基于 mPaaS 框架創(chuàng)建的應(yīng)用的默認(rèn)主題,主白底黑字藍(lán)按鈕:
定制應(yīng)用主題
每個(gè)應(yīng)用都會(huì)有自己的主題風(fēng)格,根據(jù)以下描述修改 mPaaS 應(yīng)用的默認(rèn)主題:
修改導(dǎo)航欄背景色、返回控制區(qū)域、標(biāo)題控制區(qū)域等,可重寫 AUThemeManager 類的
au_defaultTheme_extraInfo
方法,修改以下 key 對(duì)應(yīng)的返回值。接口方法
@interface AUThemeManager(AUExtendinfo) /*支付寶客戶端存在默認(rèn)主題,獨(dú)立 App 可修改該默認(rèn)值 * 在該方法中只需返回與默認(rèn)主題不同的鍵值對(duì)即可,請(qǐng)使用 AUTheme.h 中定義好的 key */ +(NSDictionary *)au_defaultTheme_extraInfo; @end /* * 例如 * +(NSDictionary*)au_defaultTheme_add_Info * { * NSMutableDictionary *dict = [INSMutableDictionary alloc] init]; * dictITITLEBAR_BACKGROUND_COLOR] = AU_COLOR_APP_GREEN; // AUTitleBar 背景色 * dit[TITLEBAR TITLE TEXTCOLOR1 = [UIColor redColor]; // AUTitleBar 標(biāo)題色 * ... * return dict; * } */
代碼示例
@implementation AUThemeManager (Portal) + (NSDictionary *)au_defaultTheme_extraInfo { NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; dict[TITLEBAR_BACKGROUND_COLOR] = @"COLOR(#108EE9,1)"; // 導(dǎo)航欄背景色 dict[TITLEBAR_LINE_COLOR] = @"COLOR(#108EE9,1)"; // 導(dǎo)航欄底部分割線或邊線的顏色 dict[TITLEBAR_TITLE_TEXTCOLOR] = @"COLOR(#ffffff,1)"; // 導(dǎo)航欄標(biāo)題色 dict[TITLEBAR_TITLE_TEXTSIZE_BOLD] = @"FONT(18)"; // 導(dǎo)航欄標(biāo)題大小 dict[TITLEBAR_TEXTCOLOR] = @"COLOR(#ffffff,1)"; // 導(dǎo)航欄返回按鈕顏色 return dict; } @end }
說明顏色值必須使用類如 COLOR(#108EE9,1) 的方式,否則會(huì)報(bào)錯(cuò)。
修改主題配置中返回按鈕圖片,需重寫 AUBarButtonItem 類中的
au_default_backButtonImg
方法。接口方法
#import "AUUILoadDefine.h"http://程序自動(dòng)生成 #ifdef ANTUI_UI_TitleBar_AUBarButtonltem//程序自動(dòng)生成 // // AUBarButtonltem+AUExtendInfo.h // AntUI // // Copyright ? 2017 Alipay. All rights reserved. // #import "AUBarButtonltem.h" @interface AUBarButtonltem(AUExtendInfo) //支付寶返回按鈕默認(rèn)是藍(lán)色 icon,獨(dú)立 App 可修改返回按鈕默認(rèn)圖標(biāo) +(UIImage *)au_default_backButtonlmg; @end
代碼示例
@implementation AUBarButtonItem (CGBBarButtonItem) + (UIImage *)au_default_backButtonImg { // 自定義返回按鈕的圖片 return APCommonUILoadImage(@"back_button_normal_white"); } @end
修改所有頁面的返回按鈕樣式和文案。
定制某一個(gè)頁面導(dǎo)航欄樣式
除了定制主題外,有時(shí)也需定制當(dāng)前頁面的導(dǎo)航欄的樣式,如修改背景顏色、返回按鈕樣式等,根據(jù)修改時(shí)機(jī)不同,mPaaS 提供了不同的方法。
頁面加載前,在默認(rèn)導(dǎo)航欄樣式基礎(chǔ)上修改導(dǎo)航欄顏色,可以在當(dāng)前頁面所在的 VC 中,實(shí)現(xiàn)
DTNavigationBarAppearanceProtocol
中的定義方法,來修改對(duì)應(yīng)區(qū)域的顏色。接口方法
@protocol DTNavigationBarAppearanceProtocol<NSObject> @optional /** 這個(gè) DTViewController 是否要自動(dòng)隱藏navigationBar,默認(rèn)為 NO。業(yè)務(wù)某個(gè) ViewController 需要隱藏 NavigationBar 可以重載此方法并返回 YES. **/ -(BOOL)autohideNavigationBar; /** 當(dāng)前 VC 隱藏導(dǎo)航欄后,如果需要設(shè)置一個(gè)全透明的導(dǎo)航欄,且當(dāng)前頁面需設(shè)置與框架邏輯一致的返回文案,請(qǐng)重載此方法,并返回一個(gè) APCustomNavigationView 的實(shí)例 -(UIView *)customNavigationBar; /** 如果某個(gè) viewcontroller 希望自己的 titlebar 是不透明,并且指定一個(gè)顏色,可以重寫這個(gè)方法,并返回希望的顏色。 * 僅限于被 Push 的 VC,tabbar 里的 VC 還是不允許修改 navigationBar 的半透明屬性 */ -(UIColor *)opaqueNavigationBarColor; /** * 如果某個(gè)viewcontroller希望修改狀態(tài)欄的樣式,請(qǐng)重寫此方法,并返回希望的style */ - (UIStatusBarStyle)customStatusBarStytle; /** * 如果某個(gè)viewcontroller希望修改導(dǎo)航欄標(biāo)題的顏色,請(qǐng)重寫此方法,并返回希望的顏色 */ - (UIColor *)customNavigationBarTitleColor;
代碼示例
#pragma mark DTNavigationBarAppearanceProtocol:進(jìn)入頁面時(shí)修改導(dǎo)航欄樣式 - (UIColor *)opaqueNavigationBarColor { // 設(shè)置當(dāng)前頁面導(dǎo)航欄背景為紅色 return [UIColor redColor]; // // 設(shè)置當(dāng)前頁面導(dǎo)航欄透明 // return [UIColor colorWithRGB:0xff0000 alpha:0]; } - (BOOL)autohideNavigationBar { // 設(shè)置當(dāng)前頁面導(dǎo)航欄是否隱藏 return NO; } - (UIStatusBarStyle)customStatusBarStytle { // 設(shè)置當(dāng)前頁面狀態(tài)欄樣式 return UIStatusBarStyleDefault; } - (UIColor *)customNavigationBarBackButtonTitleColor { // 設(shè)置當(dāng)前頁面返回按鈕文案顏色 return [UIColor greenColor]; } - (UIImage *)customNavigationBarBackButtonImage { // 設(shè)置當(dāng)前頁面返回按鈕圖片 return APCommonUILoadImage(@"back_button_normal_white"); } - (UIColor *)customNavigationBarTitleColor { // 設(shè)置當(dāng)前頁面標(biāo)題顏色 return [UIColor greenColor]; }
頁面打開后,在用戶操作的過程中動(dòng)態(tài)修改導(dǎo)航欄樣式,如背景顏色滑動(dòng)漸變、修改右側(cè)菜單按鈕等,根據(jù)修改的區(qū)域不同,主要分為以下幾類:
背景區(qū)域:包括隱藏/顯示導(dǎo)航欄、透明導(dǎo)航欄、修改導(dǎo)航欄背景顏色、修改狀態(tài)欄顏色。
- (void)gotoHideNavigator { // 隱藏導(dǎo)航欄 [self.navigationController.navigationBar setHidden:YES]; } - (void)gotoShowNavigator { // 顯示導(dǎo)航欄 [self.navigationController.navigationBar setHidden:NO]; } - (void)gotoTransparency { // 透明導(dǎo)航欄 [self.navigationController.navigationBar setNavigationBarTranslucentStyle]; } - (void)gotoUpdateBackgroundColor { // 修改導(dǎo)航欄背景顏色 [self.navigationController.navigationBar setNavigationBarStyleWithColor:[UIColor whiteColor] translucent:NO]; [self.navigationController.navigationBar setNavigationBarBottomLineColor:[UIColor whiteColor]]; } - (void)gotoUpdateStatusBarStyle { // 修改狀態(tài)欄顏色 [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent]; }
返回控制區(qū)域:修改默認(rèn)返回按鈕文案顏色、修改默認(rèn)返回按鈕返回箭頭樣式、重新設(shè)置返回按鈕樣式。
- (void)gotoUpdateBackTitleColor { // 修改默認(rèn)返回按鈕文案顏色 NSArray *leftBarButtonItems = self.navigationItem.leftBarButtonItems; if ([leftBarButtonItems count] == 1) { if (leftBarButtonItems[0] && [leftBarButtonItems[0] isKindOfClass:[AUBarButtonItem class]]) { AUBarButtonItem *backItem = leftBarButtonItems[0]; backItem.titleColor = [UIColor blackColor]; } } } - (void)gotoUpdateBackImage { // 修改默認(rèn)返回按鈕返回箭頭樣式 NSArray *leftBarButtonItems = self.navigationItem.leftBarButtonItems; if ([leftBarButtonItems count] == 1) { if (leftBarButtonItems[0] && [leftBarButtonItems[0] isKindOfClass:[AUBarButtonItem class]]) { AUBarButtonItem *backItem = leftBarButtonItems[0]; backItem.backButtonImage = APCommonUILoadImage(@"back_button_normal"); } } } - (void)gotoUpdateBackItem { // 重新設(shè)置返回按鈕樣式 self.navigationItem.leftBarButtonItem = [AUBarButtonItem barButtonItemWithImageType:AUBarButtonImageTypeDelete target:self action:@selector(onClickBack)]; } - (void)onClickBack { [self.navigationController popViewControllerAnimated:YES]; }
標(biāo)題控制區(qū)域:修改默認(rèn)標(biāo)題顏色、設(shè)置上下主副標(biāo)題、修改標(biāo)題為圖片顯示。
- (void)gotoUpdateTitleColor { // 修改標(biāo)題顏色 [self.navigationController.navigationBar setNavigationBarTitleTextAttributesWithTextColor:[UIColor blackColor]]; } - (void)gotoTwoTitle { // 修改標(biāo)題樣式:上下主副標(biāo)題 self.navigationItem.titleView = [[AUDoubleTitleView alloc] initWithTitle:@"主標(biāo)題" detailTitle:@"副標(biāo)題"]; } - (void)gotoTitleImage { // 修改標(biāo)題樣式:圖片 UIImageView *imageView = [[UIImageView alloc] initWithImage:APCommonUILoadImage(@"ilustration_ap_expection_alert")]; imageView.frame = CGRectMake(0, 0, self.self.view.width-100, 64); self.navigationItem.titleView = imageView; }
菜單控制區(qū)域:設(shè)置單個(gè)或多個(gè)右側(cè)菜單按鈕。
- (void)gotoSetOptionMenu { // 設(shè)置右側(cè)單按鈕 self.navigationItem.rightBarButtonItem = [AUBarButtonItem barButtonItemWithImageType:AUBarButtonImageTypeGroupChat target:self action:@selector(onClickRightItem)]; } - (void)gotoSetTwoOptionMenu { // 設(shè)置右側(cè)雙按鈕 AUBarButtonItem *item1 = [AUBarButtonItem barButtonItemWithImageType:AUBarButtonImageTypeGroupChat target:self action:@selector(onClickRightItem)]; AUBarButtonItem *item2 = [AUBarButtonItem barButtonItemWithImageType:AUBarButtonImageTypeHelp target:self action:@selector(onClickRightItem)]; self.navigationItem.rightBarButtonItems = @[item1, item2]; }
沉浸式導(dǎo)航欄:進(jìn)入時(shí)導(dǎo)航欄透明,滑動(dòng)到指定位置后不透明。主要分為以下兩類:
進(jìn)入頁面時(shí),設(shè)置導(dǎo)航欄透明:在當(dāng)前頁面所在的 VC 中重寫以下接口。
- (UIColor *)opaqueNavigationBarColor { // 設(shè)置當(dāng)前頁面導(dǎo)航欄透明 return [UIColor colorWithRGB:0xff0000 alpha:0]; }
頁面滑動(dòng)到指定位置后,修改導(dǎo)航欄背景區(qū)域、返回區(qū)域、標(biāo)題區(qū)域及菜單控制區(qū)域等樣式。
- (void)gotoUpdateBackgroundColor { // 修改導(dǎo)航欄背景顏色 [self.navigationController.navigationBar setNavigationBarStyleWithColor:[UIColor whiteColor] translucent:NO]; [self.navigationController.navigationBar setNavigationBarBottomLineColor:[UIColor whiteColor]]; } - (void)gotoUpdateBackTitleColor { // 修改默認(rèn)返回按鈕文案顏色 NSArray *leftBarButtonItems = self.navigationItem.leftBarButtonItems; if ([leftBarButtonItems count] == 1) { if (leftBarButtonItems[0] && [leftBarButtonItems[0] isKindOfClass:[AUBarButtonItem class]]) { AUBarButtonItem *backItem = leftBarButtonItems[0]; backItem.titleColor = [UIColor blackColor]; } } } - (void)gotoUpdateTitleColor { // 修改標(biāo)題顏色 [self.navigationController.navigationBar setNavigationBarTitleTextAttributesWithTextColor:[UIColor blackColor]]; }