当前位置: 首页 > 知识库问答 >
问题:

所有这些自动布局更新方法之间的区别是什么?都是必要的吗?

龚钧
2023-03-14

在下面的代码中,这四种方法用于布局推理。不过,我有点困惑,为什么需要所有这些工具,以及它们之间的不同之处。在这个过程中,它们用于使单元格的高度随着自动布局而动态变化。(摘自此问题的存储库。)

[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;
}

但是他们有什么不同之处?为什么他们都需要?

共有1个答案

晋承嗣
2023-03-14

假设您将视图逻辑封装在一个子类UIView中,并将其称为SomeView。这意味着SomeView应该知道如何布局自己,也就是说,如何在其中定位其他视图(您也可以创建一个不使用任何子视图就可以绘制自己的视图,但这超出了一般开发人员的需要)。

此布局由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%的布局可以被自动布局覆盖。

系统需要知道何时应该调用UIView layoutSubviews。显然,这是在您第一次需要绘制视图时完成的,但也可以在superview帧更改时调用它。这里有一个详细的解释。

因此,系统经常调用[查看布局需要]。您也可以随时调用它,但只有当有某个事件调用了[查看setNeedsLayout]或您手动调用它(如本例所示)时,此操作才会生效。

自动布局(在文档中以这种方式大写)之所以这样调用,是因为您将其保留为继承自UIView的视图,并用约束来描述子视图的位置。

使用自动布局时,系统将在每次布局过程中调用[查看更新约束条件(如果需要)]。但是,仅当标志[view setNeedsUpdateConstraints] ,则该方法将调用updateConstraints(执行实际工作)。

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

您可以像本例中那样实现它。

很少需要直接调用layoutIfNeeded和updateConstraintsIfNeeded,因为UI引擎会在每次布局过程中自动执行此操作。然而,在这种情况下,作者选择了立即给他们打电话;这是因为现在需要最终高度,而不是将来某个时候。

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

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

  1. 在视图创建过程中创建约束(手动或在IB中)
  2. 如果以后需要更改约束,请重写updateConstraints
  3. 如果具有无法用上述方法描述的复杂布局,请重写布局子视图

在更改可能导致视图约束更改的内容的代码中,调用

[view setNeedsUpdateConstraints];

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

[view updateConstraintsIfNeeded]; 

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

[view setNeedsLayout]; 

最后,如果你想立即得到结果,请致电

[view layoutIfNeeded];

这就是为什么在这种情况下需要所有四个调用。

请参阅文章《高级自动布局工具箱》(Advanced Auto Layout Toolbox,objc)中的详细说明。io问题#3

 类似资料:
  • 问题内容: 在Go的整个Google App Engine文档中,它们可互换使用库。这是一个例子: 我应该使用哪些库?主要区别是什么? 问题答案: cloud.google.com/go/datastore是Cloud Datastore rest API(可从任何地方使用)的客户端库。 google.golang.org/appengine/datastore是App Engine API的一部

  • 本文向大家介绍图片加载框架有哪些?他们之间的区别是什么?(这个也是必问的)相关面试题,主要包含被问及图片加载框架有哪些?他们之间的区别是什么?(这个也是必问的)时的应答技巧和注意事项,需要的朋友参考一下 ImageLoader : 优点: ① 支持下载进度监听; ② 可以在 View 滚动中暂停图片加载; ③ 默认实现多种内存缓存算法这几个图片缓存都可以配置缓存算法,不过 ImageLoader

  • 问题内容: 我为程序使用了HashMap,它运行良好,但是我不理解HashMap的这些初始化之间的区别。 假设我正在实现一个HashMap,以字符作为键,并以整数作为值。这些有什么区别? 问题答案: 任何涉及或不涉及类型实参的内容(尖括号<和>及其之间的部分)都是原始类型,不应使用。原始类型不是通用类型,可以让您做不安全的事情。 “正确”的方法是 第一种使用接口Map作为参考类型。它通常比较惯用,

  • 本文向大家介绍Kafka和Flume之间的主要区别是什么?相关面试题,主要包含被问及Kafka和Flume之间的主要区别是什么?时的应答技巧和注意事项,需要的朋友参考一下 答:Kafka和Flume之间的主要区别是: 工具类型 Apache Kafka——Kafka是面向多个生产商和消费者的通用工具。 Apache Flume——Flume被认为是特定应用程序的专用工具。 复制功能 Apache

  • 问题内容: 网上似乎充满了Velocity和FreeMarker之间的比较,并且它们似乎相当等效。但是,StringTemplate和FreeMarker之间似乎几乎没有比较! 那么,StringTemplate和FreeMarker之间的主要区别是什么? 我对它们的用法是仅生成HTML页面。在这两种方法中,我曾期望FreeMarker更合适,功能更强大,因为这似乎是更常见的一种- 但快速浏览一下