【问题标题】:What is the difference between all these Auto Layout update methods? Are all necessary?所有这些自动布局更新方法有什么区别?都是必须的吗?
【发布时间】:2013-12-16 19:47:23
【问题描述】:

在下面的代码中,调用了这四个方法进行布局推理。不过,我有点困惑为什么需要所有这些,以及它们之间的不同之处。它们用于通过自动布局使单元格的高度动态化。 (取自this repository 来自this question。)

[cell setNeedsUpdateConstraints];
[cell updateConstraintsIfNeeded];
[cell.contentView setNeedsLayout];
[cell.contentView layoutIfNeeded];

它来自这个单元格高度的代码块:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{

    RJTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    [cell updateFonts];

    NSDictionary *dataSourceItem = [self.model.dataSource objectAtIndex:indexPath.row];
    cell.titleLabel.text =  [dataSourceItem valueForKey:@"title"];
    cell.bodyLabel.text = [dataSourceItem valueForKey:@"body"];

    cell.bodyLabel.preferredMaxLayoutWidth = tableView.bounds.size.width - (kLabelHorizontalInsets * 2.0f);

    [cell setNeedsUpdateConstraints];
    [cell updateConstraintsIfNeeded];
    [cell.contentView setNeedsLayout];
    [cell.contentView layoutIfNeeded];

    CGFloat height = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;

    return height;
}

但他们的做法有何不同?为什么都需要它们?

【问题讨论】:

    标签: ios objective-c uiview autolayout nslayoutconstraint


    【解决方案1】:

    布局

    假设您将视图逻辑封装在UIView 子类中,并将其命名为SomeView。这意味着SomeView 应该知道如何layout 自己,即如何在其中定位一些其他视图(您也可以创建一个不使用任何子视图而绘制自身的视图,但这超出了普通开发人员的需求)。

    此布局由[SomeView layoutSubviews] 完成。您可以选择覆盖它:

    subview.frame = CGRectMake(100 + shiftX, 50 + shiftY, 250 + shiftX - paddingRight, ...
    // Oh no, I think I didn't do it right.
    

    但您很少需要这样做。在 Cocoa Touch 的黑暗时代,这种手动布局很普遍,但现在我想说 99% 的布局都可以用 Auto Layout 覆盖。

    系统需要知道何时应该调用[UIView layoutSubviews]。它显然是在您第一次需要绘制视图时完成的,但也可能在超级视图框架发生变化时调用它。 Here's a detailed explanation.

    所以系统经常调用[view layoutIfNeeded]也可以随时调用它,但这只有在某些事件已调用[view setNeedsLayout] 或您手动调用它时才会生效,如本例所示。

    约束

    Auto Layout(在the documentation 中大写)是这样调用的,因为您要离开[SomeView layoutSubviews],因为它继承自UIView 和 用约束来描述你的子视图的位置。

    使用自动布局时,系统将在每次布局传递时调用[view updateConstraintsIfNeeded]。但是,只有设置了标志[view setNeedsUpdateConstraints];,该方法才会调用-updateConstraints(真正的工作)。

    如果您不使用自动布局,则这些方法不相关。

    你可以像in this example一样实现它。

    你的例子

    很少需要直接调用-layoutIfNeeded-updateConstraintsIfNeeded,因为UI 引擎会在每次布局传递时自动执行此操作。但是,在这种情况下,作者选择立即给他们打电话;这是因为现在需要得到的高度,而不是将来的某个时候。

    这种更新单元格高度的方法似乎是正确的。请注意,cell 可能是新创建的单元格,因此尚未添加到视图层次结构中;这不会影响其自行布局的能力。

    结论

    在您的自定义视图中使用以下选项,从最“通用”到最“自定义”:

    1. 在创建视图期间创建约束(手动或在 IB 中)
    2. 如果您以后需要更改约束,请覆盖-updateConstraints
    3. 如果有无法通过上述方式描述的复杂布局,请覆盖-layoutSubviews

    在更改可能使您的视图约束发生变化的代码中,调用

    [view setNeedsUpdateConstraints];
    

    如果您需要立即获得结果,也请致电

    [view updateConstraintsIfNeeded]; 
    

    如果代码改变了视图的框架使用

    [view setNeedsLayout]; 
    

    最后,如果您想立即获得结果,请致电

    [view layoutIfNeeded];
    

    这就是在这种情况下需要所有四个调用的原因。

    附加材料

    看看Advanced Auto Layout Toolbox, objc.io issue #3文章中的详细解释

    【讨论】:

    • 对于你想要的选项现在为什么你必须调用setNeeds... 方法?如果未设置标志,随附的方法会不会触发?并且经常在与自动布局相关的动画中,您更改常量 [view layoutIfNeeded]` 被调用,但您说这是针对帧的。这是如何运作的?如果是因为自动布局确实改变了框架,那么不是每次使用自动布局都会改变框架吗?
    • 如果未设置标志,随附的方法是否不会触发? – 确实如此。
    • that's for frame.——这个方法的作用是设置布局,直接设置frame是最简单的实现,但是自动布局确实更复杂。
    • 它是如何工作的? 动画是一个完全不同的话题。如果你为约束设置动画,我的猜测是约束不会“改变”,因为 [view setNeedsUpdateConstraints] 没有被调用。
    • 我喜欢人们提出好的问题(如stackoverflow.com/questions/how-to-ask)。让回答更有趣。
    猜你喜欢
    • 1970-01-01
    • 2013-06-25
    • 1970-01-01
    • 1970-01-01
    • 2018-04-29
    • 2020-09-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多