【问题标题】:Stack view - but with "proportional" gaps堆栈视图 - 但有“比例”差距
【发布时间】:2018-07-10 20:40:35
【问题描述】:

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

注意有三个间隙,ABC。

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

(只有 间隙 会发生变化,具体取决于堆栈视图可用的整体高度。)

假设 UISV 能够绘制所有内容,例如剩下 300 个。这三个差距各为 100。

在示例中,剩下 9,因此 A B 和 C 各为 3。

但是。

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

因此 - 你的设计师可能会说类似

如果屏幕太高,请扩大 A、B 和 C 处的空间。但是。始终将 B 扩展为比 A 和 B 处的间隙快 4 倍。”

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

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

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

【问题讨论】:

  • 从 iOS 11 开始,您也可以拥有自定义间距。见here
  • 嗬@Honey!是的,我在问题中提到了这一点:它本身并不是解决问题的方法!

标签: ios autolayout uistackview


【解决方案1】:

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

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

为了让它发挥作用,我认为您必须添加一个约束,以在有可用空间的情况下尝试拉伸这些空间:

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

“正常”内容视图必须具有固有大小或显式约束设置其高度才能正常工作。

这是一个例子:

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

【讨论】:

  • 嗯,一言为定!我会检查求解器是否可以求解…………我有一种不好的感觉,它不能……
  • @Fattie 创建虚拟空间的更正确方法是使用UILayoutGuide在视图层次结构中添加虚拟视图会产生许多成本。首先,存在创建和维护视图本身的成本。其次,虚拟视图是视图层次结构的完整成员,这意味着它增加了层次结构执行的每个任务的开销。最糟糕的是,不可见的虚拟视图会截获发往其他视图的消息,从而导致难以发现的问题。
  • @Honey 听起来不错,但不起作用.. 哈哈,想用那个标语.. 无论如何,这里的问题是,如果你使用UIStackView,你可以使用@987654328 添加虚拟视图@,但没有 addArrangedLayoutGuide 添加 UILayoutGuide 作为安排的子视图/布局指南..
  • 顺便说一句,LayoutGuide 是一个很棒的,被低估的系统,你提到它真是太好了!!!
  • 圣牛 @MilanNosáľ - 看起来线性方程求解器可以解决它,你所要做的就是设置相对高度,你想要,它会解决的。神圣!!!!太不可思议了!
【解决方案2】:

创建者:a gist with a storyboard example

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

在本例中,主视图大小为 0.2(深灰色),成对内为 0.05(黑色),成对之间为 0.1(浅灰色)

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

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

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

【讨论】:

  • 该死的家伙!我可能没有很好地解释它:虽然这是对这种技术的奇妙解释,肯定会帮助很多人:我的意思是,四个黄色块固定高度。并且整体屏幕高度不同。于是,三个空隙(A、B、C)扩大——只有空隙扩大——从而填满屏幕.....
  • 如果您使用 managedSubviews 的设置高度子视图(在我的示例中为深灰色)制作实际内容视图,您可以将它们限制在顶部、底部或中心,并获得大部分效果想要。
  • 好消息是,Milan 的想法在 iOS 中确实有效,这太棒了。我包括了一个答案,只是解释了米兰的想法,包括视觉效果来轻松解释它。它的工作原理与问题完全相同。万岁,米兰!!!!!!!
【解决方案3】:

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

您无需设置任何优先级/等 - 它在 iOS 求解器中“自然”地完美运行!

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

根本不设置“gap1”的高度。

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

只需为 gap2 和 gap3 设置所需的比率!

对比 gap1。

所以,gap2 是 gap1 高度的 0.512,gap3 是 gap1 高度的 0.398,以此类推。

它确实解决了所有情况。

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

所以:在三个示例中(具有三种不同屏幕高度的手机)。 事实上,间隙的相对高度,总是相同的。您的设计部门会很高兴的! :)

【讨论】:

    猜你喜欢
    • 2021-04-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-26
    • 1970-01-01
    相关资源
    最近更新 更多