美文网首页
layoutIfNeeded和layoutSubviews

layoutIfNeeded和layoutSubviews

作者: 冷武橘 | 来源:发表于2020-04-20 09:24 被阅读0次

一般控件设置好约束后,不会立即转化成frame,而是被标记等待下一个runloop运行周期刷新,因此我们这时想直接取到控件的宽高为0

   [headView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.offset(100);
        make.left.offset(100);
        make.right.offset(-100);
        make.height.equalTo(@200);
    }];

    NSLog(@"宽:%f,高:%f",headView.frame.size.width,headView.frame.size.height);
    [headView layoutIfNeeded];
    NSLog(@"宽:%f,高:%f",headView.frame.size.width,headView.frame.size.height);

  • 调用layoutIfNeeded就会立即刷新frame后就可以获取到frame了。

1、layoutIfNeeded后一定能取到控件的大小吗?

不一定,layoutIfNeeded就会立即刷新frame,但是前提条件是父控件确定好外部约束了或者父控件的大小不能为0,否则控件即使刷新了frame也不能确定自身的frame。

 
    UIView *view = [[UIView alloc]init];
    view.backgroundColor =[UIColor greenColor];
    [headView addSubview:view];
    [view mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.right.top.bottom.equalTo(headView);
    }];
    [view layoutIfNeeded];
    NSLog(@"%f",view.frame.size.height);
    [headView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.offset(100);
        make.left.offset(100);
        make.right.offset(-100);
        make.height.equalTo(@200);
    }];
    [view layoutIfNeeded];
    NSLog(@"%f",view.frame.size.width);

这样或许我们会在开发中就会遇到了这样的问题,明明我也调用了layoutIfNeeded,但是还是为0。
比如:

@interface CourseDetailHeadView()
@end
@implementation CourseDetailHeadView
- (instancetype)initWithFrame:(CGRect)frame{
    self = [super initWithFrame:frame];
    if (self) {
       UIView *view = [[UIView alloc]init];
        [self addSubview:view];
        view.backgroundColor = [UIColor greenColor];
        [view mas_makeConstraints:^(MASConstraintMaker *make) {
            make.left.top.offset(10);
            make.right.offset(-20);
            make.bottom.offset(-100);
        }];
        [view layoutIfNeeded];
        NSLog(@"%f",view.frame.size.width);
        
    }
    return self;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    CourseDetailHeadView *headView = [[CourseDetailHeadView alloc]init];
    [self.view addSubview:headView];
    self.headView = headView;
    headView.backgroundColor = [UIColor redColor];
    [headView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.top.offset(100);
       make.right.bottom.offset(-100);
    }];
}

明明我们调用了[view layoutIfNeeded]方法,却得到的view宽度还是0,why?因为CourseDetailHeadView在初始化时,还无法确定父控件的位置约束 ,更不用说确定子控件view大小了,毕竟view的约束是依赖父控件的。

- (void)viewDidLoad {
    [super viewDidLoad];
    CourseDetailHeadView *headView = [[CourseDetailHeadView alloc]initWithFrame:CGRectMake(10, 100, 300,100)];
    [self.view addSubview:headView];
    self.headView = headView;
    headView.backgroundColor = [UIColor redColor];
}

- (instancetype)initWithFrame:(CGRect)frame{
    self = [super initWithFrame:frame];
    if (self) {
     UIView *view = [[UIView alloc]init];
      view.backgroundColor =[UIColor greenColor];
      [self addSubview:view];
      [view mas_makeConstraints:^(MASConstraintMaker *make) {
          make.left.right.top.bottom.equalTo(self);
      }];
      [view layoutIfNeeded];
      NSLog(@"%f",view.frame.size.width);
    }
    return self;
}

像这样在初始化的同时并确定好frame,这样[view layoutIfNeeded]就可以得到此时真实的frame

2、layoutSubviews什么时候调用?

layoutSubviews默认实现不做任何事情,可以用来确定子控件的frame,但你不应该直接调用该方法,如果您想强制进行布局更新,请在下一次绘图更新之前调用setNeedsLayout方法。如果您想立即更新视图的布局,请调用layoutIfNeeded方法。
什么时候调用请参考:https://www.jianshu.com/p/e6e04eb8c21d

2.1、setNeedsLayout,

  • 这个可以对视图进行标记,标记为需要布局更新,但是不会立即更新,而是会等待下一个运行循环才会去更新。
- (void)viewDidLoad {
    [super viewDidLoad];
    CourseDetailHeadView *headView = [[CourseDetailHeadView alloc]initWithFrame:CGRectMake(10, 100, 300,100)];
    [self.view addSubview:headView];
    self.headView = headView;
    headView.backgroundColor = [UIColor redColor];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    [self.headView setNeedsLayout];
}
@implementation CourseDetailHeadView
- (void)layoutSubviews{
    [super layoutSubviews];
    NSLog(@"布局子控件");
}
  • 对视图进行标记后,待下一个运行循环才会去更新,然后就会触发layoutSubviews的调用。
  • 直接调用setLayoutSubviews,一定会触发layoutSubviews的调用

2.2、layoutIfNeeded

  • 如果有需要刷新的标记,立即调用layoutSubviews进行布局
- (void)viewDidLoad {
    [super viewDidLoad];
    CourseDetailHeadView *headView = [[CourseDetailHeadView alloc]initWithFrame:CGRectMake(10, 100, 300,100)];
    [self.view addSubview:headView];
    self.headView = headView;
    headView.backgroundColor = [UIColor redColor];
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    [self.headView layoutIfNeeded];
}

-调用 layoutIfNeeded不一定会调用layoutSubviews, layoutIfNeeded顾名思义:需要刷新时布局 ,才会立即刷新,视图只有被系统或者自己标记,才会立即刷新。而这个例子中因为没有被系统标记过,自己也没标记过,不会去刷新布局,因此不会即使调用了 layoutIfNeeded也不会触发layoutSubviews。

如果你想手动去标记,并且立即再触发layoutSubviews,你可以这样。

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    [self.headView setNeedsLayout];
    [self.headView layoutIfNeeded];
}

相关文章

网友评论

      本文标题:layoutIfNeeded和layoutSubviews

      本文链接:https://www.haomeiwen.com/subject/nbaibhtx.html