如何控制嵌套在另一个堆栈视图中的 UIStackView 的相对宽度?

How do I control the relative widths of UIStackViews nested within another stack view?

我有一个相当困难的布局设计,在 iOS 中使用嵌套堆栈视图可能会更容易。但是,我在控制嵌套在其他堆栈中的堆栈的大小或分布时遇到问题。例如,如果我将 Distribution 设置为 Fit Equally,布局的一部分看起来还不错:

但是,我真正想要的是照片和容器的宽度约为文本字段堆栈宽度的 1/3。如果我将 Distribution 设置为 Fit Proportionally,则堆叠图像(不改变大小)和容器展开并将文本挤压到显示器的一侧。我读到的所有内容都建议降低内容压缩阻力优先级。我已经在图像、容器和堆栈视图本身上进行了尝试,但效果不佳。

有人能给我指出正确的方向来控制嵌套在其他堆栈中的堆栈的相对宽度吗?

我希望可能有更好的答案,但我发现的唯一有效方法是将图像放入视图并将其固定到视图的边缘。然后可以使用约束来控制视图的大小。

如果有人有更好的方法,他们仍然可以回答这个更详细的问题的一部分:

回答您的问题:有人可以指出正确的方向来控制嵌套在其他堆栈中的堆栈的相对宽度吗? ...

问题是你的顶层 UIStackView 在决定​​如何分配额外的 space/squash 东西放在一起,基于每个子视图的 returned intrinsicContentSize 和它们的 contentHuggingPriority/contentCompressionResistance。不幸的是,UIStackView 本身 - 即你的 nested UIStackView - return 对它自己 intrinsicContentSize 没有任何用处(尽管它有它自己的子视图,其中做)。因此,顶级 UIStackView 只是向前推进并进行布局,就好像嵌套的 UIStackView 不在乎一样,这就是为什么您的嵌套 UIStackView 最终比您想要的更宽。

我很幸运地为嵌套子类使用了一个简单的 UIStackView 子类,return 是一个有用的 intrinsicContentSize 基于它自己的内容的宽度(对于垂直轴) 或高度(对于水平轴),如下:

@implementation NestedStackView
- (CGSize)intrinsicContentSize
{
    CGSize size = [super intrinsicContentSize]; // returns {UIViewNoIntrinsicMetric,UIViewNoIntrinsicMetric}

    for (UIView *view in self.arrangedSubviews)
        if (!view.hidden) { // UIStackView ignores hidden subviews when doing its layout; so should we...
            if (self.axis == UILayoutConstraintAxisVertical) {
                size.width = MAX(view.intrinsicContentSize.width, size.width);
            } else {
                size.height = MAX(view.intrinsicContentSize.height, size.height);
            }
        }
    return size;
}
@end

通过这样做,顶级 UIStackView 现在在分配其 [=41] 时会考虑 nested UIStackView 所需的内容宽度=]. [旁白:我首先尝试在嵌套的 UIStackView 的宽度上添加一个明确的 NSLayoutConstraint,但它被忽略了。而 returning 一个 instrinsicContentSize.width 有效]

一种简单的方法是使用 AutoLayout 在嵌套的堆栈视图上设置相对宽度限制。例如,如果您想让左 UIStackView 填充屏幕的 2/3,而右 UIStackView 填充 1/3,您可以使用下面的代码。

let leftStackView = UIStackView(arrangedSubviews: [...])
leftStackView.axis = .vertical

let rightStackView = UIStackView(arrangedSubviews: [...])
rightStackView.axis = .vertical

let containerStackView = UIStackView(arrangedSubviews:
                                     [leftStackView, rightStackView])

containerStackView.axis = .horizontal
containerStackView.distribution = .fillProportionally
containerStackView.translatesAutoresizingMaskIntoConstraints = false

addSubview(containerStackView)

//leftStackView will be twice as wide as the rightStackView, so 
//the distribution is 2/3rds to 1/3rd
leftStackView.widthAnchor.constraint(equalTo:
  rightStackView.widthAnchor, multiplier: 2.0).isActive = true