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