1. 程式人生 > >iOS--UINavigationController學習筆記

iOS--UINavigationController學習筆記

1.簡介         UINavigationController:是iOS常見的一種容器型Controller。官方文件上給出的註釋如下  UINavigationController manages a stack of view controllers and a navigation bar.It performs horizontal view transitions for pushed and popped views while keeping the navigation bar in sync.Most clients will not need to subclass UINavigationController.
If a navigation controller is nested in a tabbar controller, it uses the title and toolbar attributes of the bottom view controller on the stack.UINavigationController is rotatable if its top view controller is rotatable.Navigation between controllers with non-uniform rotatability is currently not supported.
意思是說,UINavigationController管理著一個viewController的棧和一個navigation bar(navigation bar後面會說)。管理著出於同一層次的viewController的view,包括壓棧和出棧(viewController顯示滑進和隱藏滑出界)的轉場動畫,同時還同步管理著頂部navigation bar的狀態。大部分的app都不需要實現一個它的子類(對於一般的功能,都具有支援)。如果一個UINavigationController的例項巢狀在一個UITabbarController的例項中,它將使用棧底的viewController的標題和toolbar的屬性。UINavigationController的可旋轉是和棧頂的viewController保持一致的。現在還不支援同一層次的viewController旋轉型別不一致的壓棧出棧。 2.常見屬性和方法
- (instancetype)initWithRootViewController:(UIViewController *)rootViewController;  以一個viewController為棧底,例項化一個navigation viewcontroller - (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated;  展示一個viewcontroller,壓棧操作(可以有動畫效果)。 - (nullableUIViewController *)popViewControllerAnimated:(BOOL)animated;  結束並隱藏一個viewcontroller(dealloc),出棧操作(可以有動畫效果),返回出棧的viewcontroller - (nullableNSArray<__kindofUIViewController *> *)popToViewController:(UIViewController *)viewController animated:(BOOL)animated;  結束並隱藏 在棧中位於一個特殊的viewcontroller之前所有的viewcontroller,並返回 - (nullableNSArray<__kindofUIViewController *> *)popToRootViewControllerAnimated:(BOOL)animated; 出棧到根viewcontroller @property(nullable,nonatomic,readonly,strong) UIViewController *topViewController;  棧頂viewcontroller @property(nullable,nonatomic,readonly,strong) UIViewController *visibleViewController;  如果模態viewcontroller存在,返回模態viewcontroller,否則棧頂viewcontroller @property(nonatomic,copy) NSArray<__kindofUIViewController *> *viewControllers;  當前棧中的元素 - (void)setViewControllers:(NSArray<UIViewController *> *)viewControllers animated:(BOOL)animated NS_AVAILABLE_IOS(3_0);  設定棧中的元素,animated=yes,根據當前的棧頂viewcontroller在不在這個viewcontroller陣列中,模擬一次push和pop的動畫。這就相當於對當前的棧進行了一次整體的重新整理 下面的bar屬性主要是用來顯示頂部的導航欄以及底部的工具欄 @property(nonatomic,getter=isNavigationBarHidden)BOOLnavigationBarHidden; - (void)setNavigationBarHidden:(BOOL)hidden animated:(BOOL)animated;  @property(nonatomic,readonly) UINavigationBar *navigationBar;  @property(nonatomic,getter=isToolbarHidden)BOOLtoolbarHidden NS_AVAILABLE_IOS(3_0) __TVOS_PROHIBITED; - (void)setToolbarHidden:(BOOL)hidden animated:(BOOL)animated NS_AVAILABLE_IOS(3_0) __TVOS_PROHIBITED;  @property(null_resettable,nonatomic,readonly) UIToolbar *toolbar NS_AVAILABLE_IOS(3_0) __TVOS_PROHIBITED;//  delegate,可以在壓棧出棧操作中,設定一些動畫,以及一些額外的操作 @property(nullable,nonatomic,weak)id<UINavigationControllerDelegate> delegate; 這裡需要說一下visibleViewController和topViewController:topViewController永遠代表著棧頂元素;visibleViewController代表著當前顯示的那個vc,這個vc可能是top vc,也有可能是top vc 展示出來的vc。 3.UINavigationBar 3.1. 導航欄屬性設定:        通常我們都會在APPDelegate為整個APP的導航欄做全域性性的設定,使用[UINavigationBarappearance]這個方法獲得當前的導航欄例項;以及在viewController中對當前頁面的導航欄做特殊的設定,使用self.navigationController.navigationBar獲得當前的導航欄例項。記住,在viewController中對導航欄的設定,要在這個viewController小時之前還原,否則會覆蓋全域性的設定,從而影響其他頁面的顯示。       barTintColor:設定導航欄的整體背景顏色,包括狀態列的背景顏色。如下:  [[UINavigationBarappearance]setBarTintColor:[UIColoryellowColor]];執行的效果如下                           tintColor:設定導航欄的按鈕的圖示和文字顏色(系統提供的),自定義的不在此範圍;  [[UINavigationBarappearance]setTintColor:[UIColorredColor]];執行的效果如下                           barStyle:設定導航欄的整體風格,有UIBarStyleDefault和UIBarStyleBlack兩種選擇。對應以下兩種執行結果,可以看到UIBarStyleBlack會影響狀態列的顏色以及導航欄的標題顏色。(但是已經對標題的字型顏色都已經賦值的,就不受影響了)                          titleTextAttributes:設定導航欄的標題的顯示樣式,包括UITextAttributeFont - 字型 UITextAttributeTextColor - 文字顏色  UITextAttributeTextShadowColor - 文字陰影顏色    UITextAttributeTextShadowOffset - 偏移用於文字陰影        [[UINavigationBarappearance]setTitleTextAttributes:[NSDictionarydictionaryWithObjectsAndKeys:                                                    [UIColorredColor],NSForegroundColorAttributeName,                                                    [UIFontsystemFontOfSize:18.f],NSFontAttributeName,                                                   nil]];                     backgroundImage/shadowImage:設定導航欄的背景和陰影圖片     [[UINavigationBarappearance]setBackgroundImage:[UIImageimageNamed:xxx] forBarMetrics:UIBarMetricsDefault];     [[UINavigationBarappearance]setShadowImage:[UIImageimageNamed:xxx]]; translucent:BOOL,半透明效果。         補充點:前面說到也可以在viewController中對UINavigationBar進行屬性設定,基本上都會生效。但是,有些情況下會發現,viewController的(UIStatusBarStyle)preferredStatusBarStyle是不起作用的,原因是因為當前的viewController是巢狀在一個UINavigationController的例項中,最多隻會呼叫UINavigationController的preferredStatusBarStyle,除非將導航欄隱藏,才會呼叫viewController的preferredStatusBarStyle方法。解決辦法:在iOS9之前,App的info.plist檔案中,新增View controller-based status bar appearance的值為NO,(意識是說讓Application的設定優先於viewController的設定),通過[[UIApplication sharedApplication] setStatusBarStyle:]這個方法來進行設定修改statusBar;但是在iOS9之後,該方法會提示過時⚠️,解決辦法是將 View controller-based status bar appearance的值設定YES,然後通過navigationBar.barStyle來設定。然而,現在很多應用都是在iOS7做適配的時候,將View controller-based status bar appearance設為NO,(iOS之前,預設值為NO,iOS之後為YES),iOS7和8對此也都處於相容狀態。9之後會出現警告。 3.2. UINavigationItem以及其與UINavigationBar的關係: 在前面的簡介之中,提到UINavigationController管理著一個UIViewController的棧和一個UINavigationBar。其實,一個UINavigationController的例項對應一個UINavigationBar的例項,而一個UINavigationBar的例項同樣管理著一個棧,這個棧中的元素就是UINavigationItem。所以,既然一個navigationController對應一個navigationBar,可以推斷到UINavigationController的棧和UINavigationBar的棧也是對應的,而兩個棧裡元素也是一一對應,也就是一個UIViewController的例項也對應著一個UINavigationItem的例項(如果不對應,系統會報異常情況)。在navigationController進行push和pop的同時,navigationBar也在同時做相應的push和pop 。在官方的API中,在UINavigationController.h檔案中會有一個UIViewController的一個category,裡面定義著一個UINavigationItem的變數。 3.3.  定製導航欄內容        定製導航欄一般都是在viewController中進行自我定製navigationItem。        定製title,使用viewController.title和viewController.navigationItem.title都可以實現導航欄title的定製。補充:設定viewController.title會覆蓋viewController.navigationItem.title,設定viewController.navigationItem.title不會覆蓋viewController.title。        有的時候需要將導航欄標題修改為一個我們自己想要的UIView,只要將我們需要的UIView賦值給viewController.navigationItem.titleView。比如一個button,一張圖片,一個搜尋框等等        定製left/rightBarButtonItem:在導航欄中,左右兩邊通常都會有一些button或者需要互動的view。這時候就需要給viewController.navigationItem設定left/rightBarButtonItem,可定製成任意樣式。        在導航欄中,如果本身沒有對viewController.navigationItem.leftBarButtonItem進行定製,會優先展示上一個頁面的backBarButtonItem;如果上一個頁面也沒有設定backBarButtonItem,就會展示一個系統的回退按鈕和上一個頁面的title。