动态添加子视图 UIView 的正确方法
很多时候哥比较喜欢用代码添加视图,特别是要同时加很多UIView时,而且跟 xib 比起来代码更容易管理,在多人的项目中代码不容易 conflict。
但小牛哥最近发现很多新人都不太清楚正确的使用方法,以下是哥的一些总结,有何不妥欢迎大家一起讨论:
(前提条件是这样的:有一个 View Controller 和相应的 xib 文件,我们需要为这个controller 动态加上其他的子视图)
UIViewController 中动态添加 UIView 正确的步骤应该是:
1. 在 viewDidLoad 中创建要添加的 UIView (UILabel, UIImageView, UIButton 等等)。像这样: UIButton *aButton = [[UIButton alloc] initWithFrame:…] 为什么不能在 viewWillAppear 中创建?根据苹果的文档,这里是添加 last minute 修改的地方,比如修改视图的位置,颜色等等。如果在这里创建很多视图,会导致显示延迟。
2. 创建的时候最好为每个 UIView 加上约束(NSLayoutConstraint),这样在不同大小的屏幕中都可以正确显示。
3. 不用约束也行,必须在 viewDidLayoutSubviews 中修改视图的 frame。
对于一些简单的视图确实没必要加上约束,但是没有约束会导致视图在不同大小的屏幕中的 frame 不好看,这时就得在这里修改 frame, 对,只能在这里: viewDidLayoutSubviews 里修改。
为什么呢?
首先咱来复习一下 UIViewController 的生命周期:
A: init…
B: loadView
C: viewDidLoad
D: viewWillAppear
E: viewWillLayoutSubviews
F: viewDidLayoutSubviews
G: viewDidAppear
H: viewWillDisappear
I: viewDidDisappear
J: viewDidUnload (not used any more)
K: dealloc…
现在咱可以做个实验: 在项目中选一个View Contorller ,它的 xib 中的视图大小为 600×600, 在其 .m 文件中以上的 C, D,E,F,G方法打印出视图的frame,像这样:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
NSLog(@"%s self.view.frame: %@", __PRETTY_FUNCTION__, NSStringFromCGRect(self.view.frame));
}
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
NSLog(@"%s self.view.frame: %@", __PRETTY_FUNCTION__, NSStringFromCGRect(self.view.frame));
}
-(void)viewWillLayoutSubviews
{
NSLog(@"%s self.view.frame: %@", __PRETTY_FUNCTION__, NSStringFromCGRect(self.view.frame));
}
-(void)viewDidLayoutSubviews
{
NSLog(@"%s self.view.frame: %@", __PRETTY_FUNCTION__, NSStringFromCGRect(self.view.frame));
}
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
NSLog(@"%s self.view.frame: %@", __PRETTY_FUNCTION__, NSStringFromCGRect(self.view.frame));
}
选择设备为 iPhone 5, 运行程序后会得到类似这样的结果:
[TaskDetailsViewController viewDidLoad] self.view.frame: {{0, 0}, {600, 600}}
[TaskDetailsViewController viewWillAppear:] self.view.frame: {{0, 0}, {600, 600}}
[TaskDetailsViewController viewWillLayoutSubviews] self.view.frame: {{0, 0}, {320, 568}}
[TaskDetailsViewController viewDidLayoutSubviews] self.view.frame: {{0, 0}, {320, 568}}
[TaskDetailsViewController viewDidAppear:] self.view.frame: {{0, 0}, {320, 568}}
大家可以看到,一个视图的大小是在调用 viewWillLayoutSubviews 时才会根据设备而改变,不过在 IOS 8 中,要到viewDidLayoutSubviews 才正确。根视图的大小改变了,子视图必须相应做出调整才可以正确显示,这就是为什么要在 viewDidLayoutSubviews 中调整动态视图的frame。
By the way,在 IOS 9 中,根视图控件(Root View Controller)的视图大小在 viewDidLoad 中就已经正确了,苹果好像会不时改变这些特点,比如会把系统键盘的视图优先级提高等等。所以小牛哥觉得动态添加视图最安全的方法是,创建视图后马上加上约束,不管日后苹果怎么改都可以正确显示。
关于如何动态添加约束,大家可以看看这里:
http://matthewmorey.com/creating-uiviews-programmatically-with-auto-layout/
相关文章
- 用 query 方法 获得xml 节点的值
- VS2015中添加新建项,找不到ado .net entity datamodel的解决方法
- 测试用例经典设计方法之 因果图法
- 浅谈现场质量改善的思路和方法
- java基础—自定义一个比较器,对TreeSet 集合中的元素按指定方法来排序(java集合六)
- AndroidStudio中添加第三库文件的方法
- 添加dubbo.xsd的方法
- 《实践者的研究方法》—— 第2章 软件工程 2.5 这一切是如何开始的
- 在Linux下打包tar文件时添加密码的方法
- 在Linux下打包tar文件时添加密码的方法
- MFC中动态创建控件及添加消息响应的方法实例
- VS2013以上版本加载VisionPro控件的方法
- iOS 运行时添加属性和方法
- DRF 3.x Request and Response 请求和响应使用示例和配置方法
- Vuex--mutations属性--方法,---响应式添加 vue.set(对象,属性)删除vue.delete数据
- vue---向后台添加数据--删除数据--事件方法传参---在单页面配置url请求地址--暂时没有用到webpack
- Windows提示 错误: RPC 服务器不可用 解决方法。
- React之JSX里render中return方法添加括号()或者[]
- 用css3选择器给你要的第几个元素添加不同样式方法【转发】
- java 动态代理(模式) InvocationHandler(为类中方法执行前或后添加内容)
- Java加载资源文件的两种方法
- 纯html实现将网页页面分享到微信朋友圈添加缩略图图片的方法
- 【Verilog基础】在不同时钟域之间如何安全地传递信号方法总结(2)单比特跨时钟域之结绳法(快到慢)
- Android学习之添加自定义对话框图标的方法
- OC中字符串的提取与替换-四种不同方法实现
- Runtime 方法替换 和 动态添加实例方法 结合使用
- JavaScript之向文档中添加元素和内容的方法