我想补充一下n8gray的回答,在某些情况下,您需要拨打setNeedsLayout
然后layoutIfNeeded
。
比方说,您编写了一个扩展UIView的自定义视图,其中子视图的位置很复杂,无法使用autoresizingMask或iOS6 AutoLayout完成。定制定位可以通过覆盖layoutSubviews
来完成。
举个例子,假设您有一个自定义视图,该视图具有contentView
属性和edgeInsets
属性,该属性允许设置contentView周围的边距。 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方法如下,并呼吁其次layoutIfNeeded
setNeedsLayout
:
- (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);
}];
如果不添加调用layoutIfNeeded在setEdgeInsets方法,动画将无法工作,因为layoutSubviews将在下一个更新周期,这相当于调用它的动画块外调用。
如果只调用setEdgeInsets方法中的layoutIfNeeded,则不会设置setNeedsLayout标志。
谢谢 - 很高兴有人终于回答了这个问题。在此期间,我还必须深入研究setNeedsDisplay - 它会导致drawRect被调用 - 和contentMode。只有contentMode = UIViewContentModeRedraw将导致setNeedsDisplay在视图边界更改时被调用。其他contentMode选项只会导致视图缩放,移动一定量,或者与边缘对齐。我的自定义UITableViewCell不想重新定位方向更改,它只会缩放,直到我将contentMode设置为UIViewContentModeRedraw。 – Tarfa 2010-05-29 13:08:05
我想你的代码中的[self.subview1 layoutSubviews]应该替换为[self.subview1 setNeedsLayout]。由于layoutSubviews意味着被覆盖,但并不意味着从另一个视图调用。框架决定何时调用它(通过将多个布局请求分组为一个调用以提高效率),或者通过在视图层次结构中的某个位置调用layoutIfNeeded来间接执行此操作。 – Tarfa 2010-05-29 13:20:25
更正以上我的评论:“...由于layoutSubviews是意图被覆盖或从自己调用,但并不意味着被调用或从另一个视图...” – Tarfa 2010-05-29 13:29:01