堆栈视图 - 但有 "proportional" 个间隙

Stack view - but with "proportional" gaps

想象一下有四个项目的堆栈视图,正在填充一些东西。 (比如说,填满屏幕)。

注意有三个个空格,ABC。

(注意 - 每个黄色方块的高度都是固定的。)

(只有 gaps 变化,具体取决于堆栈视图可用的整体高度。)

假设 UISV 可以绘制所有内容,还剩下 300 个。三个差距将各为100。

例子中还剩9个,所以A B和C各3个。

但是

很多时候,您希望差距本身享有比例关系

因此-您的设计师可能会说

If the screen is too tall, expand the spaces at A, B and C. However. Always expand B let's say 4x as fast as the gaps at A and B."

所以,如果剩下“12”,那就是 2,8,2。而当剩下 18 时,那就是 3,12,3。

这个概念在堆栈视图中可用吗?否则,你会怎么做?

(请注意,最近添加到堆栈视图中,您确实可以单独指定间隙。因此,可以“手动”执行此操作,但这将是一团糟,您将与很多求解器。)

您可以通过以下解决方法来实现。代替间距,为每个 space 添加一个新的 UIView(),这将是一个可伸缩的 space。然后只需在这些 "spaces" 的高度之间添加约束,这将根据您想要的乘数将它们的高度约束在一起,例如:

space1.heightAnchor.constraint(equalTo: space2.heightAnchor, multiplier: 2).isActive = true

为了让它发挥作用,我认为您必须添加一个约束来尝试拉伸那些 space,以防有空闲 space:

let stretchingConstraint = space1.heightAnchor.constraint(equalToConstant: 1000)
// lowest priority to make sure it wont override any of the rest of constraints and compression resistances
stretchingConstraint.priority = UILayoutPriority(rawValue: 1)
stretchingConstraint.isActive = true

"normal" 内容视图必须具有固有的大小或明确的限制来设置它们的高度才能正常工作。

这是一个例子:

class MyViewController: UIViewController {

    fileprivate let stack = UIStackView()

    fileprivate let views = [UIView(), UIView(), UIView(), UIView()]
    fileprivate let spaces = [UIView(), UIView(), UIView()]

    override func viewDidLoad() {
        super.viewDidLoad()

        self.view.backgroundColor = .white

        self.view.addSubview(stack)

        // let stack fill the whole view
        stack.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            stack.topAnchor.constraint(equalTo: self.view.topAnchor),
            stack.bottomAnchor.constraint(equalTo: self.view.bottomAnchor),
            stack.leftAnchor.constraint(equalTo: self.view.leftAnchor),
            stack.rightAnchor.constraint(equalTo: self.view.rightAnchor),
            ])

        stack.alignment = .fill
        // distribution must be .fill
        stack.distribution = .fill
        stack.spacing = 0
        stack.axis = .vertical

        for (index, view) in views.enumerated() {
            stack.addArrangedSubview(view)
            view.translatesAutoresizingMaskIntoConstraints = false
            // give it explicit height (or use intrinsic height)
            view.heightAnchor.constraint(equalToConstant: 50).isActive = true

            view.backgroundColor = .orange

            // intertwin it with spaces
            if index < spaces.count {
                stack.addArrangedSubview(spaces[index])
                spaces[index].translatesAutoresizingMaskIntoConstraints = false
            }
        }
        // constraints for 1 4 1 proportions
        NSLayoutConstraint.activate([
            spaces[1].heightAnchor.constraint(equalTo: spaces[0].heightAnchor, multiplier: 4),
            spaces[2].heightAnchor.constraint(equalTo: spaces[0].heightAnchor, multiplier: 1),
            ])

        let stretchConstraint = spaces[0].heightAnchor.constraint(equalToConstant: 1000)
        stretchConstraint.priority = UILayoutPriority(rawValue: 1)
        stretchConstraint.isActive = true
    }
}

已创建:a gist with a storyboard example

此处的关键是 Equal Heights 排列视图和参考视图之间: 然后将“乘数”更改为您想要的大小:

在此示例中,主视图尺寸(深灰色)为 0.2,成对尺寸(黑色)为 0.05,成对尺寸尺寸为 0.1(浅灰色)

然后简单地更改包含视图的大小将导致视图按比例重新调整大小:

这完全在故事板中,但您可以在代码中做同样的事情。

请注意,我只使用 StackView 内的比例以避免总尺寸不正确(并确保它们加起来等于 1.0),但也应该可以设置一些高度如果正确完成,在 StackView 内。

值得注意的是,@MilanNosáľ 的解决方案非常有效。

您不需要设置任何 priorities/etc - 它在 iOS 求解器中完美地工作 "naturally"!

将四个内容区域简单地设置为50个固定高度。 (使用任何内在内容项。)

根本不设置 "gap1" 的高度。

将 gap2 和 gap3 设置为与 gap1 的高度相等。

简单 - 为 gap2 和 gap3 设置您想要的比率!

与差距 1.

因此,gap2 是 gap1 高度的 0.512,gap3 是 gap1 高度的 0.398,等等

它确实解决了所有情况。

太棒了!!!!!!!!!!!

因此:在三个示例中(具有三种不同屏幕高度的手机)。 其实差距的相对高度,总是一样的。你的设计部门会很高兴! :)