什么是的UIView的setNeedsLayout,layoutIfNeeded和layoutSub

2019-05-12 12:49发布

谁能给上之间的关系明确的解释UIView's setNeedsLayoutlayoutIfNeededlayoutSubviews方法呢? 和示例实现所有三个将被使用。 谢谢。

是什么让我感到困惑的是,如果我把我的自定义查看setNeedsLayout消息,它会调用后,这个方法是非常接下来的事情layoutSubviews ,跳绳就在layoutIfNeeded 。 从文档我预计流量将setNeedsLayout >导致layoutIfNeeded被称为>导致layoutSubviews调用。

Answer 1:

我还在试图弄清楚这一点我自己,所以如果它包含错误借此与一些怀疑和原谅。

setNeedsLayout是一个简单的一个:它只是在标记为需要布局的UIView设置一个标志的地方。 这将迫使layoutSubviews下一重绘发生之前要对视图调用。 请注意,在很多情况下,你不需要因为的显式调用, autoresizesSubviews属性。 如果是这样的设置(它是通过默认),则任何改变视图的帧将导致视图布置其子视图。

layoutSubviews是你做的所有有趣的事情的方法。 这相当于drawRect的布局,如果你愿意。 一个简单的例子可能是:

-(void)layoutSubviews {
    // Child's frame is always equal to our bounds inset by 8px
    self.subview1.frame = CGRectInset(self.bounds, 8.0, 8.0);
    // It seems likely that this is incorrect:
    // [self.subview1 layoutSubviews];
    // ... and this is correct:
    [self.subview1 setNeedsLayout];
    // but I don't claim to know definitively.
}

AFAIK layoutIfNeeded一般不意味着在子类中被覆盖。 这是你注定当你想要一个观点是正确的,现在布局调用的方法。 苹果的实现可能是这个样子:

-(void)layoutIfNeeded {
    if (self._needsLayout) {
        UIView *sv = self.superview;
        if (sv._needsLayout) {
            [sv layoutIfNeeded];
        } else {
            [self layoutSubviews];
        }
    }
}

你会打电话layoutIfNeeded上以迫使它(以及它的superviews必要)立即布置。



Answer 2:

我想在n8gray的回答补充一点,在某些情况下,你需要调用setNeedsLayout通过遵循layoutIfNeeded

比方说,比如你写扩展UIView的自定义视图,其子视图的定位是复杂的,不能用autoresizingMask或iOS6的自动版式来完成。 自定义定位可以通过重写来完成layoutSubviews

举个例子,假设你有,有一个自定义视图contentView属性和edgeInsets属性,允许设置围绕内容查看边距。 layoutSubviews是这样的:

- (void) layoutSubviews {
    self.contentView.frame = CGRectMake(
        self.bounds.origin.x + self.edgeInsets.left,
        self.bounds.origin.y + self.edgeInsets.top,
        self.bounds.size.width - self.edgeInsets.left - self.edgeInsets.right,
        self.bounds.size.height - self.edgeInsets.top - self.edgeInsets.bottom); 
}

如果你希望能够随时更改动画帧变化edgeInsets财产,你需要重写edgeInsets setter方法如下,并呼吁setNeedsLayout其次layoutIfNeeded

- (void) setEdgeInsets:(UIEdgeInsets)edgeInsets {
    _edgeInsets = edgeInsets;
    [self setNeedsLayout]; //Indicates that the view needs to be laid out 
                           //at next update or at next call of layoutIfNeeded, 
                           //whichever comes first 
    [self layoutIfNeeded]; //Calls layoutSubviews if flag is set
}

这样,如果你做到以下几点,如果你改变了动画块内的edgeInsets财产的内容查看的帧变化将动画。

[UIView animateWithDuration:2 animations:^{
    customView.edgeInsets = UIEdgeInsetsMake(45, 17, 18, 34);
}];

如果不加调用layoutIfNeeded在setEdgeInsets方法,动画将无法工作,因为layoutSubviews将在下一个更新周期,这相当于调用它的动画块外调用。

如果你只叫layoutIfNeeded在setEdgeInsets方法,因为setNeedsLayout标志未设置会发生什么。



文章来源: What is the relationship between UIView's setNeedsLayout, layoutIfNeeded and layoutSubviews?