Ios 对于依赖于已解决内部布局的大小,正确实现intrinsicContentSize

Ios 对于依赖于已解决内部布局的大小,正确实现intrinsicContentSize,ios,layout,uiview,uilabel,autolayout,Ios,Layout,Uiview,Uilabel,Autolayout,我有一个似乎有效的解决方案,但我想确保它是安全的,并按预期使用该工具。我可以把我的问题归结到这个场景——我有一个UIView,它包含多个垂直堆叠的UILabel。每个标签都可以填充任意文本,垂直包装和展开标签。在视图中堆叠标签的自动布局约束非常简单。我想做的是让UIView通过intrinsicContentSize向其所有者传达其首选高度(视图的高度应适合所有标签)。但是,内部布局需要先解决,然后才能返回适当的高度。我的理解是,从[super layoutSubviews]返回后,解算器保证是

我有一个似乎有效的解决方案,但我想确保它是安全的,并按预期使用该工具。我可以把我的问题归结到这个场景——我有一个UIView,它包含多个垂直堆叠的UILabel。每个标签都可以填充任意文本,垂直包装和展开标签。在视图中堆叠标签的自动布局约束非常简单。我想做的是让UIView通过
intrinsicContentSize
向其所有者传达其首选高度(视图的高度应适合所有标签)。但是,内部布局需要先解决,然后才能返回适当的高度。我的理解是,从
[super layoutSubviews]
返回后,解算器保证是完整的,这就是我正在做的:

- (void)layoutSubviews
{
    [super layoutSubviews];

    // solver's complete, now we can measure?
    [self invalidateIntrinsicContentSize];
}
My
intrinsicContentSize
实现引用最后一个标签的框架来计算高度。这一切似乎对我目前的情况有效,但它让我感到紧张。似乎解算器在布局其内部构件时会要求当前视图的intrinsicContentSize。我将不详细介绍,但我遇到了一个案例,在这个案例中,这个模式旋转成一个无限循环。我可以通过调整一些布局代码来解决这个问题-这并没有激发信心

有更好的方法吗?这似乎是一件很平常的事情,当我开始解决这个问题时,我认为这就是intrinsicContentSize的用途。我所看到的intrinsicContentSize的实现一直都是琐碎的——一个维度的硬编码大小,或者测量不依赖于已解决的内部布局的单个视图

注意,我不能只使用
NSString sizeWith…
方法测量标签,因为内部布局太复杂了

注意,我使用了
systemLayoutSizeFittingSize:
,但是从intrinsicContentSize调用它会导致无限循环


如有任何回应,将不胜感激!提前谢谢

这是我为这个问题想出的解决方案。 如果要为封装其他
NSView
实例的
NSView
提供
intrinsicContentSize
,则有两种可能性。或者所有子视图都有
intrinsicContentSize
值,您可以使用这些值,否则至少有一个
NSViewNoInstrinsicMetric
值,您需要依赖这些子视图的布局结果来计算
intrinsicContentSize

在第二种情况下,您的
intrinsicContentSize
取决于其子视图的帧值,您需要对这些帧的任何更改作出反应,就像标签对其包含的文本的任何更改作出反应一样。您可以使用
NSViewFrameDidChangeNotification
执行此操作。下面是我如何在自定义的
NSView
子类中执行此操作的:

- (void)didAddSubview:(NSView *)subview
{
    [super didAddSubview:subview];
    subview.postsFrameChangedNotifications = YES;
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(subviewFrameDidChange:) name:NSViewFrameDidChangeNotification object:subview];
    [self setNeedsUpdateConstraints:YES];
    [self invalidateIntrinsicContentSize];
}

- (void)willRemoveSubview:(NSView *)subview
{
    [super willRemoveSubview:subview];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:NSViewFrameDidChangeNotification object:subview];
    [self setNeedsUpdateConstraints:YES];
    [self invalidateIntrinsicContentSize];
}

- (void)subviewFrameDidChange:(NSNotification*)notif
{
    [self invalidateIntrinsicContentSize];
}

我想更新这个帖子并结束这个问题-我认为对于其他刚开始使用AutoLayout的人来说,这里仍然有价值,他们可能会有类似的误解。理解intrinsicContentSize的真正用途很重要-这不是典型视图如何将其首选大小传递给其父视图。如果视图使用“自动布局”来布局其子视图,则它将使用定义其内部布局的约束来通知其父视图的大小-具体地说,将子视图与其父视图关联的约束将帮助定义父视图的大小。这实际上是AutoLayout的一部分,它既神奇又令人沮丧——是所有这些约束(视图的内部和外部)的总和导致了布局。只有在视图不使用AutoLayout定义其大小的情况下(例如UILabel或UIImageView的典型情况),才真正需要内部大小


我认为,与多行文本相关的早期iOS错误/不一致是我走向intrinsicContentSize的原因。多行文字仍然不是完美的,但希望在iOS10中更好。

你找到解决方法了吗?自从我发布这篇文章以来,我没有学到任何新东西。我提出的解决方案一直运作良好,但它仍然让我有点紧张,而且不清楚这是否是正确的方法。有没有其他人有过这种模式或替代模式的运气?谢谢我不能同意你的看法<代码>intrinsicContentSize可以通过实现。可能是你想要的。@Dawnson:你可能是对的,我已经有几年没有做iOS开发了,所以我没有跟上新增加的内容。