关于 UIView 的 layoutSubviews 方法

来源:互联网 发布:电脑控制器软件 编辑:程序博客网 时间:2024/06/01 09:43

关于 UIView 的 layoutSubviews 方法

UIKit 的 UIView 是一个非常重要的类,几乎每个尝试 iOS 开发的程序员都会用到它。UIView 本身实现了 Composite Pattern,所以一个应用的界面最终可以由一群树状组合的 UIView 来组合而成——在这棵 UIView 树的最顶部,是继承于 UIView 的 UIWindow 实例,然后是由 UIWindow 实例保有的 rootViewController 的根 UIView 实例,然后是在该 UIView 实例上的各种各样的子节点 UIView。

父 UIView 可以拥有自己的子 UIView,自然而然的,父 UIView 就会面对用怎样的策略来布局、排列这些子 UIView 的问题。在 UIView 中,UIKit 的开发者专门提供了 layoutSubviews 方法来解决这个问题。

官方文档对于该方法有如下的描述:

Subclasses can override this method as needed to perform more precise layout of their subviews. You should override this method only if the autoresizing and constraint-based behaviors of the subviews do not offer the behavior you want. You can use your implementation to set the frame rectangles of your subviews directly.

如果你需要更加精确的布局,可以在子类里面重写这个方法.仅仅在以下情况下:自动布局达不到你想要效果时你才有必要重写这个方法.你可以直接设置subviews的尺寸.

You should not call this method directly. If you want to force a layout update, call the setNeedsLayout method instead to do so prior to the next drawing update. If you want to update the layout of your views immediately, call the layoutIfNeeded method.

你不能直接调用这个方法.如果你需要强制layout刷新,调用setNeedsLayout来代替.如果你想要立即刷新你的view,调用layoutIfNeeded.

layoutSubviews什么时候会被调用,看下面:

1、init初始化不会触发layoutSubviews。
2、addSubview会触发layoutSubviews。
3、设置view的Frame会触发layoutSubviews,当然前提是frame的值设置前后发生了变化。
4、滚动一个UIScrollView会触发layoutSubviews。
5、旋转Screen会触发父UIView上的layoutSubviews事件。
6、改变一个UIView大小的时候也会触发父UIView上的layoutSubviews事件。
7、直接调用setLayoutSubviews。
8、直接调用setNeedsLayout。

下面是部分验证学习(错误的地方请大家指出来,相互学习):

#import "ViewController.h"#import "TestView.h"@interface ViewController ()@property(nonatomic,strong) NSTimer *timer;@property(nonatomic,strong) TestView *bigView;@property(nonatomic,strong) TestView *smallView;@end@implementation ViewController- (void)viewDidLoad {    [super viewDidLoad];    // Do any additional setup after loading the view, typically from a nib.    //    // [self test1];    // [self test2];       [self test3];    // [self test4];    // [self test5];}-(void)test1{    TestView *test1=[[TestView alloc]initWithFrame:CGRectMake(100, 100, 100, 100)];    //打印结果为:initWithFrame:{{100, 100}, {100, 100}}.所以init初始化不会触发layoutSubviews.}-(void)test2{    TestView *test1=[[TestView alloc]init];    [self.view addSubview:test1];    //打印结果为:initWithFrame:{{0, 0}, {0, 0}}.    TestView *test2=[[TestView alloc]initWithFrame:CGRectZero];    [self.view addSubview:test2];    //打印结果为:initWithFrame:{{0, 0}, {0, 0}}    TestView *test3=[[TestView alloc]initWithFrame:CGRectMake(100, 100, 100, 100)];    [self.view addSubview:test3];    //打印结果为:initWithFrame:{{100, 100}, {100, 100}},layoutSubviews <TestView: 0x7af63860; frame = (100 100; 100 100); layer = <CALayer: 0x7af45240>>    //由上测试可知:addSubview会触发layoutSubviews.除了frame值为{{0, 0}, {0, 0}}的情况.}-(void)test3{    TestView *test1=[[TestView alloc]initWithFrame:CGRectMake(100, 100, 100, 100)];    [self.view addSubview:test1];}- (void)test4{    CGRect rect = self.view.bounds;    CGFloat height = rect.size.height;    CGFloat width  = rect.size.width;    UIScrollView *rootScroll= [[UIScrollView alloc] initWithFrame:self.view.bounds];    NSArray *data= @[@"1", @"2", @"3", @"4"];    [data enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {    TestView *tmp= [[TestView alloc] initWithFrame:CGRectMake(width*idx+50, 80,width*0.7, height*0.7)];        tmp.backgroundColor=[UIColor redColor];        [rootScroll addSubview:tmp];    }];    rootScroll.contentSize   = CGSizeMake(width * data.count, height);    rootScroll.pagingEnabled=YES;    [self.view addSubview:rootScroll];    /*     程序一运行就直接打印如下:     initWithFrame:{{50, 80}, {224, 397.60001}}     initWithFrame:{{370, 80}, {224, 397.60001}}     initWithFrame:{{690, 80}, {224, 397.60001}}     initWithFrame:{{1010, 80}, {224, 397.60001}}     layoutSubviews <TestView: 0x7a97d9f0; frame = (1010 80; 224 397.6); layer = <CALayer: 0x7a9755b0>>     layoutSubviews <TestView: 0x7a875fa0; frame = (690 80; 224 397.6); layer = <CALayer: 0x7a8753b0>>     layoutSubviews <TestView: 0x7a97d8b0; frame = (370 80; 224 397.6); layer = <CALayer: 0x7a973720>>     layoutSubviews <TestView: 0x7a764b30; frame = (50 80; 224 397.6); layer = <CALayer: 0x7a7649a0>>     当我滚动UIScrollView的时候,并没有触发layoutSubviews.     */}- (void)test5{    _timer = [NSTimer scheduledTimerWithTimeInterval:1.f                                              target:self                                            selector:@selector(timerEvent:)                                            userInfo:nil                                             repeats:YES];    _bigView = [[TestView alloc] initWithFrame:self.view.bounds];    [self.view addSubview:_bigView];    _smallView = [[TestView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];    [_bigView addSubview:_smallView];}- (void)timerEvent:(id)sender{    _smallView.frame = CGRectMake(arc4random()%100 + 20,                                  arc4random()%100 + 20,                                  arc4random()%100 + 20,                                  arc4random()%100 + 20);    NSLog(@"_smallView %@", _smallView);    NSLog(@"_bigView %@", _bigView);    //由打印结果可知:改变一个UIView大小的时候也会触发父UIView上的layoutSubviews.}

这里是自定义 view:

#import <UIKit/UIKit.h>@interface TestView : UIView@end#import "TestView.h"@implementation TestView-(id)initWithFrame:(CGRect)frame{    self = [super initWithFrame:frame];    if (self) {        NSLog(@"initWithFrame:%@",NSStringFromCGRect(frame));    }    return self;}-(void)layoutSubviews{    NSLog(@"layoutSubviews %@",self);    [super layoutSubviews];}

@end

这里有一篇英文文档:
http://blog.logichigh.com/2011/03/16/when-does-layoutsubviews-get-called/

0 0
原创粉丝点击