代码细节
@interface ZKRRootViewController : UIViewController
/**
内容视图,是 view 的子视图,大小为去除状态栏的屏幕大小,
所有的其他视图内容都应放在该视图内
*/
@property (nonatomic, strong) UIView *contentView;
/**
显示导航栏使用该属性,自动调整 contentView 的位置
*/
@property (nonatomic, assign) BOOL isNavigationBarShow;
@implementation ZKRRootViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = UIColor.whiteColor;
[self.view addSubview:self.contentView];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
self.navigationController.navigationBarHidden = YES;
}
- (UIView *)contentView {
if (_contentView == nil) {
//个人热点开启时,需要调整位置
CGFloat originY = StatusBarHeight - self.view.frame.origin.y;
_contentView = [[UIView alloc]initWithFrame:CGRectMake(0, originY,
WindowFrameWidth, WindowFrameHeight - StatusBarHeight)];
}
return _contentView;
}
@end
通常,设计框架时,会定义一个根控制器,以便处理一些通用操作,并且会自定义一个控制器视图的子视图作为所有视图的容器,如上。
并且在第一次获取 contentView
的时候,会根据控制器视图的位置来调整其位置,以避免个人热点开启,或雷达开启时对视图布局的影响。
但是,这里也需要注意一下代码的执行顺序,如下:
ZKRRootViewController *root = [[ZKRRootViewController alloc]init];
root.contentView.backgroundColor = UIColor.redColor;
如果在执行 self.view
之前,执行了 self.contentView
,那么此时便会执行 CGFloat originY = StatusBarHeight - self.view.frame.origin.y;
,而在执行该语句时,会访问 self.view
从而触发 loadView
方法的执行,虽然此处并未重写该方法。但是,接着便会执行 viewDidLoad
方法,而该方法里又访问了 self.contentView
,此时的 _contentView
仍是无值状态,所以会再次执行创建过程,并且这一次会创建成功,并将该视图添加到控制器视图中。然后,退出 viewDidLoad
方法,进而 CGFloat originY = StatusBarHeight - self.view.frame.origin.y;
语句执行完毕。
此时,_contentView
已经有值,并且已经被添加到 view
中,但接着执行下面的语句:
_contentView = [[UIView alloc]initWithFrame:CGRectMake(0, originY, WindowFrameWidth, WindowFrameHeight - StatusBarHeight)];
会覆盖原 _contentView
的值,并且返回,从而设置 backgroundColor
为红色。
但是,最终显示的视图并不是红色的,因为 _contentView
并未添加到 view
中,而如果接着将其添加到 view
中,那么在 viewDidLoad
中对 _contentView
的操作将被覆盖。总之,这是因为在创建 _contentView
的过程中,重复执行获取其本身的代码所造成的。