Iphone UIView和#x27之间的关系是什么;s setNeedsLayout、LayoutFneed和LayoutSubview?

Iphone UIView和#x27之间的关系是什么;s setNeedsLayout、LayoutFneed和LayoutSubview?,iphone,xcode,uiview,Iphone,Xcode,Uiview,有谁能对UIView的setNeedsLayout、layoutIfNeeded和layoutSubview方法之间的关系给出明确的解释?以及一个示例实现,其中将使用这三种方法。谢谢 让我感到困惑的是,如果我向自定义视图发送一条setNeedsLayout消息,它在该方法之后调用的下一个东西就是layoutSubviews,直接跳过layoutIfNeeded。从文档中,我希望流是setNeedsLayout>原因layoutIfNeeded原因layoutSubview被调用。我自己仍在努力解

有谁能对
UIView的
setNeedsLayout
layoutIfNeeded
layoutSubview
方法之间的关系给出明确的解释?以及一个示例实现,其中将使用这三种方法。谢谢


让我感到困惑的是,如果我向自定义视图发送一条
setNeedsLayout
消息,它在该方法之后调用的下一个东西就是
layoutSubviews
,直接跳过
layoutIfNeeded
。从文档中,我希望流是
setNeedsLayout
>原因
layoutIfNeeded
原因
layoutSubview
被调用。

我自己仍在努力解决这个问题,所以对此持怀疑态度,如果它包含错误,请原谅我

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
layoutifneed
通常不意味着在子类中被重写。这是一种方法,当您希望立即布置视图时,您应该调用它。苹果的实现可能如下所示:

-(void)layoutIfNeeded {
    if (self._needsLayout) {
        UIView *sv = self.superview;
        if (sv._needsLayout) {
            [sv layoutIfNeeded];
        } else {
            [self 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); 
}

您可以对视图调用
layoutifneed
,以强制立即对其进行布局(以及必要时的超级视图)。

我想补充n8gray的回答,在某些情况下,您需要调用
setNeedsLayout
,然后调用
layoutifneed

比如说,您编写了一个扩展UIView的自定义视图,其中子视图的定位非常复杂,无法使用autoresizingMask或iOS6 AutoLayout完成。自定义定位可以通过覆盖
布局子视图
来完成

例如,假设您有一个自定义视图,它有一个
contentView
属性和一个
edgeInsets
属性,允许设置contentView周围的边距<代码>布局子视图
如下所示:

-(void)layoutIfNeeded {
    if (self._needsLayout) {
        UIView *sv = self.superview;
        if (sv._needsLayout) {
            [sv layoutIfNeeded];
        } else {
            [self 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
设置器,并调用
setNeedsLayout
然后调用
layoutifneed

- (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属性,则contentView的帧更改将设置动画

[UIView animateWithDuration:2 animations:^{
    customView.edgeInsets = UIEdgeInsetsMake(45, 17, 18, 34);
}];
如果不添加对setEdgeInsets方法中所需的LayoutIfNeed的调用,动画将无法工作,因为LayoutSubView将在下一个更新周期中被调用,这相当于在动画块外部调用它


如果只调用setEdgeInsets方法中需要的LayoutIfNeed,则不会发生任何事情,因为setNeedsLayout标志未设置。

谢谢-很高兴终于有人回答了这个问题。与此同时,我还必须深入研究setNeedsDisplay(这导致调用drawRect)和contentMode。当视图的边界更改时,只有contentMode=UIViewContentModeRedraw会导致调用setNeedsDisplay。其他contentMode选项只会使视图缩放、移动一定量或与边缘对齐。我的自定义UITableViewCell不希望在方向更改时重新绘制,它只会进行缩放,直到我将ContentModerRaw设置为UIViewContentModerRaw。我认为代码中的[self.subview1 layoutSubviews]应该替换为[self.subview1 setNeedsLayout]。因为layoutSubviews意味着被覆盖,但不意味着从另一个视图或从另一个视图调用。框架决定何时调用它(通过将多个布局请求分组到一个调用中以提高效率),或者您通过调用视图层次结构中某个位置的layoutIfNeeded间接地执行此操作。更正我的上述评论:“…因为layoutSubviews意味着被覆盖或从self调用,但不意味着从另一个视图调用或从另一个视图调用…”我真的不确定
[subview1 layoutSubviews]
。很可能像
drawRect
,你不应该直接调用它。但我不确定在布局阶段调用
setNeedsLayout
是否会导致视图在同一个布局阶段进行布局,或者延迟到下一个布局阶段。如果有人能给出答案,那就太好了y了解这一切是如何工作的……或者在设置边缘插入后,您应该能够在动画块内调用
[self layoutifneed]