在項(xiàng)目開發(fā)中,所有控制器里面大概都有共同的屬性,比如背景色、導(dǎo)航欄、tarBar 的設(shè)置等等,這時(shí)我們一般都會(huì)設(shè)計(jì)出來一個(gè)
UIViewController
的基類,通常叫做baseViewController
或rootViewController
,在這個(gè)類里面設(shè)置所有控制器的共同的屬性,然后項(xiàng)目中所有的控制器再繼承自這個(gè)類。
一般來說這種基類控制器里面需要做的操作有以下幾個(gè):
- 為 APP 設(shè)置統(tǒng)一的背景色
- 設(shè)置是否允許控制器自動(dòng)調(diào)整高度(一般是 NO)
- 自定義導(dǎo)航欄返回按鈕
- 重新布局視圖大小,及時(shí)更新視圖的 frame
當(dāng)然還有其它的一些,畢竟這和項(xiàng)目的具體需求息息相關(guān),因此還要因項(xiàng)目而異。我這里主要就列出基類控制器中基本的常用的一些需求,和大家分享下,希望能幫到需要的人,少走彎路;另外文章如果有不足之處,也希望各位同行能多多的交流指點(diǎn)。
</br>
UIViewController 基類控制器設(shè)計(jì)步驟
首先創(chuàng)建一個(gè) UIViewController
類,命名為 NNBaseViewController
接著在 NNBaseViewController.m
中做一些操作
1.設(shè)置應(yīng)用的統(tǒng)一背景色
// 設(shè)置應(yīng)用的背景色
self.view.backgroundColor = [UIColor lightGrayColor];
2.將 automaticallyAdjustsScrollViewInsets 設(shè)置為NO,不然視圖會(huì)下移64像素
// 不允許 viewController 自動(dòng)調(diào)整,我們自己布局;如果設(shè)置為YES,視圖會(huì)自動(dòng)下移 64 像素
self.automaticallyAdjustsScrollViewInsets = NO;
3.有時(shí)候系統(tǒng)的返回按鈕不符合應(yīng)用的風(fēng)格,所以就需要重寫導(dǎo)航欄上的返回按鈕
#pragma mark - 自定義返回按鈕
- (void)setupLeftBarButton {
// 自定義 leftBarButtonItem ,UIImageRenderingModeAlwaysOriginal 防止圖片被渲染
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc]
initWithImage:[[UIImage imageNamed:@"Back-藍(lán)"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]
style:UIBarButtonItemStylePlain
target:self
action:@selector(leftBarButtonClick)];
// 防止返回手勢失效
self.navigationController.interactivePopGestureRecognizer.delegate = (id<UIGestureRecognizerDelegate>)self;
}
#pragma mark - 返回按鈕的點(diǎn)擊事件
- (void)leftBarButtonClick {
[self.navigationController popViewControllerAnimated:YES];
}
當(dāng)然這里需要判斷一下,不然首層控制器的導(dǎo)航欄上也會(huì)被設(shè)置上返回按鈕 leftBarButtonItem
,我是在 - (void)viewDidLoad
方法中判斷的。
// 判斷是否有上級頁面,有的話再調(diào)用
if ([self.navigationController.viewControllers indexOfObject:self] > 0) {
[self setupLeftBarButton];
}
4.接下來我們一起設(shè)置下 View
中視圖的布局,根據(jù)視圖中控件的最大的 Y 值和最大的 X 值調(diào)整 View
的 frame
。這個(gè)主要用在視圖中控件比較多的時(shí)候,也需要具體分析,比如有時(shí)候應(yīng)用中全是 UITableView
,那么就不需要設(shè)置了,因?yàn)?UITableView
可以根據(jù) cell
自動(dòng)調(diào)整 frame
。不過也有用到的時(shí)候,比如應(yīng)用中需要計(jì)算高度的類有很多,那么就可以用這個(gè)統(tǒng)一設(shè)置,主要還是看項(xiàng)目需求。另外注意這個(gè)方法要放在 - (void)viewWillAppear:(BOOL)animated
中。
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
CGFloat baseViewHeight = 0;
CGFloat baseViewWidth = 0;
NSArray *subViews = self.baseView.subviews;
// 遍歷視圖中的所有控件,求出最大的Y值和最大的X值
for (UIView *view in subViews) {
if (CGRectGetMaxY(view.frame) > baseViewHeight) {
baseViewHeight = CGRectGetMaxY(view.frame);
}
if (CGRectGetMaxX(view.frame) > baseViewWidth) {
baseViewWidth = CGRectGetMaxX(view.frame);
}
}
// 三目運(yùn)算方法求出最大的寬是否大于屏幕寬,以及最大的高是否大于屏幕高
CGFloat NNHeight = baseViewHeight > NNBaseViewSizeHeight ? baseViewHeight:NNBaseViewSizeHeight;
CGFloat NNWidth = baseViewWidth > NNBaseViewSizeWidth ? baseViewWidth:NNBaseViewSizeWidth;
self.baseView.contentSize = CGSizeMake(NNWidth, NNHeight);
}
上面代碼塊中用到了一個(gè)屬性 baseView
, baseView
屬于 UIScrollView
類,相當(dāng)于一個(gè)子視圖容器,所有繼承自 NNBaseViewController
的控制器都應(yīng)該把子視圖添加到 baseView
上,這樣才能更新它的 frame
。
#import <UIKit/UIKit.h>
@interface NNBaseViewController : UIViewController
/** 子視圖容器 */
@property (nonatomic, strong) UIScrollView *baseView;
@end
另外別忘了在 - (void)viewDidLoad
這個(gè)方法中創(chuàng)建baseView
并設(shè)置它的屬性。
self.baseView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 64, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height - 64)];
// 是否反彈
self.baseView.bounces = NO;
// 是否顯示滾動(dòng)指示器
self.baseView.showsVerticalScrollIndicator = NO;
self.baseView.showsHorizontalScrollIndicator = NO;
[self.view addSubview:self.baseView];
self.baseView.contentSize = NNContentSize;
上面便是一個(gè)基本的 UIViewController
的基類,具體還是要根據(jù)項(xiàng)目的需要來設(shè)計(jì)。
</br>
接下來是完整的代碼:
NNBaseViewController.h
#import <UIKit/UIKit.h>
@interface NNBaseViewController : UIViewController
/** 子視圖容器 */
@property (nonatomic, strong) UIScrollView *baseView;
@end
NNBaseViewController.m
#import "NNBaseViewController.h"
#define NNBaseViewSize self.baseView.bounds.size
#define NNBaseViewSizeHeight self.baseView.bounds.size.height
#define NNBaseViewSizeWidth self.baseView.bounds.size.width
@interface NNBaseViewController ()
@end
@implementation NNBaseViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self setupViews];
// 判斷是否有上級頁面,有的話再調(diào)用
if ([self.navigationController.viewControllers indexOfObject:self] > 0) {
[self setupLeftBarButton];
}
}
- (void)setupViews {
// 設(shè)置應(yīng)用的背景色
self.view.backgroundColor = [UIColor lightGrayColor];
// 不允許 viewController 自動(dòng)調(diào)整,我們自己布局;如果設(shè)置為YES,視圖會(huì)自動(dòng)下移 64 像素
self.automaticallyAdjustsScrollViewInsets = NO;
self.baseView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 64, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height - 64)];
// 是否反彈
self.baseView.bounces = NO;
// 是否顯示滾動(dòng)指示器
self.baseView.showsVerticalScrollIndicator = NO;
self.baseView.showsHorizontalScrollIndicator = NO;
[self.view addSubview:self.baseView];
self.baseView.contentSize = NNBaseViewSize;
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
CGFloat baseViewHeight = 0;
CGFloat baseViewWidth = 0;
NSArray *subViews = self.baseView.subviews;
// 遍歷視圖中的所有控件,求出最大的Y值和最大的X值
for (UIView *view in subViews) {
if (CGRectGetMaxY(view.frame) > baseViewHeight) {
baseViewHeight = CGRectGetMaxY(view.frame);
}
if (CGRectGetMaxX(view.frame) > baseViewWidth) {
baseViewWidth = CGRectGetMaxX(view.frame);
}
}
// 三目運(yùn)算方法求出最大的寬和最大的高
CGFloat NNHeight = baseViewHeight > NNBaseViewSizeHeight ? baseViewHeight:NNBaseViewSizeHeight;
CGFloat NNWidth = baseViewWidth > NNBaseViewSizeWidth ? baseViewWidth:NNBaseViewSizeWidth;
self.baseView.contentSize = CGSizeMake(NNWidth, NNHeight);
}
#pragma mark - 自定義返回按鈕
- (void)setupLeftBarButton {
// 自定義 leftBarButtonItem ,UIImageRenderingModeAlwaysOriginal 防止圖片被渲染
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc]
initWithImage:[[UIImage imageNamed:@"Back-藍(lán)"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]
style:UIBarButtonItemStylePlain
target:self
action:@selector(leftBarButtonClick)];
// 防止返回手勢失效
self.navigationController.interactivePopGestureRecognizer.delegate = (id<UIGestureRecognizerDelegate>)self;
}
#pragma mark - 返回按鈕的點(diǎn)擊事件
- (void)leftBarButtonClick {
[self.navigationController popViewControllerAnimated:YES];
}