关于 UIView 的 layoutSubviews 方法

关于 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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值