記錄狀態欄和導航欄的設置和控制,統一在基類視圖控制器中完成。 狀態欄。 狀態欄高度為20,iOS7以後背景完全透明。 樣式枚舉如下: typedef NS_ENUM(NSInteger, UIStatusBarStyle) { UIStatusBarStyleDefault = 0, // Dark ...
記錄狀態欄和導航欄的設置和控制,統一在基類視圖控制器中完成。
狀態欄。
狀態欄高度為20,iOS7以後背景完全透明。
樣式枚舉如下:
typedef NS_ENUM(NSInteger, UIStatusBarStyle) {
UIStatusBarStyleDefault = 0, // Dark content, for use on light backgrounds
UIStatusBarStyleLightContent NS_ENUM_AVAILABLE_IOS(7_0) = 1, // Light content, for use on dark backgrounds
UIStatusBarStyleBlackTranslucent NS_ENUM_DEPRECATED_IOS(2_0, 7_0, "Use UIStatusBarStyleLightContent") = 1,
UIStatusBarStyleBlackOpaque NS_ENUM_DEPRECATED_IOS(2_0, 7_0, "Use UIStatusBarStyleLightContent") = 2,
} ;
動畫枚舉如下:
typedef NS_ENUM(NSInteger, UIStatusBarAnimation) {
UIStatusBarAnimationNone,
UIStatusBarAnimationFade,
UIStatusBarAnimationSlide,
} ;
舊的常用設置方式:
[[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationFade];
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleDefault];
但是iOS9以後廢棄了這些方法。就算是在iOS7上,如果啟用了基於UIViewController的狀態欄控制系統,上述方法也將失效。
UIApplication.h中的註釋內容為:Setting the statusBarStyle/statusBarHidden does nothing if your application is using the default UIViewController-based status bar system.
iOS7以後預設開啟了UIViewController的狀態欄控制系統。如果需要關閉,並採用舊的設置方式,可以將Info.plist中鍵值View controller-based status bar appearance設置為NO。
新的設置方式:
- (UIStatusBarStyle)preferredStatusBarStyle; // Defaults to UIStatusBarStyleDefault
- (BOOL)prefersStatusBarHidden; // Defaults to NO
- (UIStatusBarAnimation)preferredStatusBarUpdateAnimation; // Defaults to UIStatusBarAnimationFade
// This should be called whenever the return values for the view controller's status bar attributes have changed. If it is called from within an animation block, the changes will be animated along with the rest of the animation block.
- (void)setNeedsStatusBarAppearanceUpdate;
上述方法,均為UIViewController的實例方法,前三個方法可以在子類中被重寫,最後主動調用setNeedsStatusBarAppearanceUpdate才會生效。
為了便於切換控制方式,提供巨集控制方案:
1.在Info.plist文件中增加鍵值View controller-based status bar appearance = NO
2.在基類控制器的頭文件中定義如下巨集,便於子類檢查是否啟用該巨集定義
//使用基於視圖控制器的狀態欄控制系統,UIApplication的setStatusBarHidden類似方法將無效
//開啟此巨集定義,請將Info.plist中View controller-based status bar appearance設置為YES,否則置為NO
#define UseDefaultUIViewControllerBasedStatusBarSystem
3.提供相關屬性以設置狀態欄,提供相關方法更新狀態欄,併在實現文件中增加條件判斷巨集
#ifdef UseDefaultUIViewControllerBasedStatusBarSystem - (UIStatusBarStyle)preferredStatusBarStyle { return self.statusBarStyle; } - (BOOL)prefersStatusBarHidden { return self.willHideStatusBar; } - (UIStatusBarAnimation)preferredStatusBarUpdateAnimation { return UIStatusBarAnimationFade; } #endif - (void)updateStatusBar { #ifdef UseDefaultUIViewControllerBasedStatusBarSystem [self setNeedsStatusBarAppearanceUpdate]; #else [[UIApplication sharedApplication] setStatusBarHidden:self.willHideStatusBar withAnimation:UIStatusBarAnimationFade]; [[UIApplication sharedApplication] setStatusBarStyle:self.statusBarStyle]; #endif }
導航欄
導航欄高44,iOS7以後預設透明,由UINavigationBar的translucent屬性決定。
1.設置導航欄顯示屬性,更多是在設置UINavigationController的UINavigationBar屬性。UIViewController中也存在UINavigationController類型的屬性,參考如下:
[self.navigationController.navigationBar setBarStyle:UIBarStyleDefault];
[self.navigationController.navigationBar setTranslucent:YES];
[self.navigationController.navigationBar setBackgroundImage:[ImageHelper getImageWithColor:NaviBarColor] forBarMetrics:UIBarMetricsDefault];
[self.navigationController.navigationBar setShadowImage:[ImageHelper getImageWithColor:NaviBarShadowColor]];
[self.navigationController.navigationBar setTitleTextAttributes:NaviBarTitleAttributes];
2.設置標題、按鈕相關屬性,關註UIViewController的UINavigationItem屬性
3.隱藏導航欄,可以設置navigationBarHidden屬性,但建議使用方法
- (void)setNavigationBarHidden:(BOOL)hidden animated:(BOOL)animated; // Hide or show the navigation bar. If animated, it will transition vertically using UINavigationControllerHideShowBarDuration.
如果上一個界面顯示導航欄,下一個界面隱藏導航欄(帶有返回上一個界面的功能方法),界面切換可能出現導航欄過渡效果不佳的情況。在viewWillAppear方法中,使用代碼
[self.navigationController setNavigationBarHidden:self.willHideNavigationBar animated:animated];
可以得到較好的切換效果。
4.如果帶有bottomBar,當新的UIViewController將要被push到導航棧top前,可以使用UIViewController的hidesBottomBarWhenPushed控制bottomBar顯示
5.合理使用導航欄控制的屬性viewControllers和方法:
- (void)setViewControllers:(NSArray<UIViewController *> *)viewControllers animated:(BOOL)animated NS_AVAILABLE_IOS(3_0); // If animated is YES, then simulate a push or pop depending on whether the new top view controller was previously in the stack.
可以實現導航棧中的視圖控制器切換、替換、新增、移除等功能效果。
6.導航控制的如下代理方法,可以實現切換動畫的自定義,後續記錄一個實現返回手勢控制的分類將涉及到
- (nullable id <UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController
interactionControllerForAnimationController:(id <UIViewControllerAnimatedTransitioning>) animationController NS_AVAILABLE_IOS(7_0);
- (nullable id <UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
animationControllerForOperation:(UINavigationControllerOperation)operation
fromViewController:(UIViewController *)fromVC
toViewController:(UIViewController *)toVC NS_AVAILABLE_IOS(7_0);
UIViewController的self.view佈局問題
單獨一個視圖控制器的self.view應該是充滿容器的,origin為(0, 0),增加導航欄以後,如果不設置,仍然為(0, 0),將增加subview佈局的麻煩。所以,需要關註如下屬性:
@property(nonatomic,assign) UIRectEdge edgesForExtendedLayout NS_AVAILABLE_IOS(7_0); // Defaults to UIRectEdgeAll
@property(nonatomic,assign) BOOL extendedLayoutIncludesOpaqueBars NS_AVAILABLE_IOS(7_0); // Defaults to NO, but bars are translucent by default on 7_0.
extendedLayoutIncludesOpaqueBars屬性,該屬性表示是否包括不透明bars,預設不包括,但是iOS7以後,狀態欄和導航欄都是預設透明的,所以self.view預設與屏幕邊緣貼合。
edgesForExtendedLayout決定了self.view與邊緣的距離,預設貼合邊框,當增加導航欄以後,需要設置為UIRectEdgeNone,使self.view上邊緣與導航欄下邊緣貼合。
下圖為self.edgesForExtendedLayout = UIRectEdgeNone;
說明:導航欄下的紅條origin為(0, 0)且高20,黑條高44,藍條高44。
下圖為self.edgesForExtendedLayout = UIRectEdgeAll;
無導航欄時候,兩種設置,紅條都靠著頂部。
UIViewController的automaticallyAdjustsScrollViewInsets屬性。
該屬性自動設置self.view上scrollView類型的subview的insets,預設為YES。
當導航欄隱藏時候,該屬性會導致scrollView的contentView的offsetY自動為20,也就是看到scrollView內容從狀態欄下邊緣開始顯示,這也將帶來很多麻煩。
所以導航欄隱藏時候設置self.automaticallyAdjustsScrollViewInsets = !willHideNavigationBar;可以避免意外的顯示異常。
下一篇記錄一個實現返回手勢的分類。
base項目已更新:[email protected]:ALongWay/base.git