动态添加子视图 UIView 的正确方法

Posted 小敏的博客

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了动态添加子视图 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/

以上是关于动态添加子视图 UIView 的正确方法的主要内容,如果未能解决你的问题,请参考以下文章

在 ScrollView 中动态填充 UIView

动态添加 UIView,还是创建 UITableView? IOS

如何在 iOS 中将 UIView 添加到 UIScrollView 中(具有动态内容的视图)

iPhone UIView - 调整框架以适应子视图

xCode:从动态添加的子视图中激活 IBAction

UIView:将 UIViewController 的视图添加为子视图并将其删除