Autolayout 我可以将 CenterY 与顶部和底部约束结合使用吗?

Autolayout Can I combine CenterY with Top and Bottom Constraints?

我正试图让这个布局以某种方式动态化。这里的选项是动态的(未知数量),因此我们可以轻松地将这些选项放在 tableView、collectionView 或只是简单的 scrollView 中。

问题是我想让这个白色容器尽可能小并且垂直居中。当我将 centerY 约束与 Top+Bottom insets 结合使用时,似乎只有顶部和底部约束被激活。

And when the options are quite long, options can be scrollable, BUT maintaining the fact that there are top and bottom insets.

心里已经有了一些想法,比如观察container view的高度是否超过设备高度

我用的是snapKit,但是约束应该是可以理解的。这是我当前的布局:

func setupUI() {

        self.view.backgroundColor = .clear

        self.view.addSubviews(
            self.view_BGFilter,
            self.view_Container
        )

        self.view_BGFilter.snp.makeConstraints {
            [=10=].edges.equalToSuperview()
        }

        self.view_Container.snp.makeConstraints {
            [=10=].centerY.equalToSuperview().priority(.high)
            //[=10=].top.bottom.greaterThanOrEqualToSuperview().inset(80.0).priority(.medium)
            [=10=].leading.trailing.equalToSuperview().inset(16.0)
        }

        // Setup container
        self.view_Container.addSubviews(
            self.label_Title,
            self.stackView,
            self.button_Submit
        )

        self.label_Title.snp.makeConstraints {
            [=10=].top.equalToSuperview().inset(40.0)
            [=10=].leading.trailing.equalToSuperview().inset(16.0)
        }

        self.stackView.snp.makeConstraints {
            [=10=].top.equalTo(self.label_Title.snp.bottom).offset(29.0)
            [=10=].leading.trailing.equalToSuperview().inset(24.0)
        }

        self.button_Submit.snp.makeConstraints {
            [=10=].height.equalTo(52.0)
            [=10=].top.equalTo(self.stackView.snp.bottom).offset(30.0)
            [=10=].bottom.leading.trailing.equalToSuperview().inset(24.0)
        }

        self.generateButtons()
    }

我回答你的问题 - CenterY 有顶部和底部约束? - 附带一点评论...

我知道 SnapKit 很受欢迎,我敢肯定它有时会很有帮助,尤其是如果您一直使用它的话。

但是...在使用它时,您永远无法完全确定它在做什么。而且,根据我的经验,使用 SnapKit 的人通常并不真正理解约束是什么或它们是如何工作的(并不意味着 you 就是这种情况......只是观察观察各种问题)。

在这种特定情况下,要么是 SnapKit 有一点错误,要么是这一行不太适合预期的结果:

[=10=].top.bottom.greaterThanOrEqualToSuperview().inset(80.0)

你可以通过简单的测试来确认:

class TestViewController: UIViewController {

    let testView: UIView = {
        let v = UIView()
        v.backgroundColor = .red
        return v
    }()

    override func viewDidLoad() {
        super.viewDidLoad()

        view.addSubview(testView)

        testView.snp.makeConstraints {
            [=11=].centerY.equalToSuperview()

            // height exactly 200 points                
            [=11=].height.equalTo(200.0)

            // top and bottom at least 80 points from superview
            [=11=].top.bottom.greaterThanOrEqualToSuperview().inset(80.0)

            [=11=].leading.trailing.equalToSuperview().inset(16.0)
        }

    }

}

这是结果...以及调试控制台中的 [LayoutConstraints] Unable to simultaneously satisfy constraints. 消息:

如果我们按如下方式替换该行:

        // replace this line
        //[=12=].top.bottom.greaterThanOrEqualToSuperview().inset(80.0)

        // with these two lines
        [=12=].top.greaterThanOrEqualToSuperview().offset(80.0)
        [=12=].bottom.lessThanOrEqualToSuperview().offset(-80.0)

这肯定似乎在做同样的事情,我们得到了我们预期的结果:

所以,SnapKit 中有些东西是可疑的。

这将解决您的问题。像这样更改 view_Container 约束设置:

    self.view_Container.snp.makeConstraints {
        [=13=].centerY.equalToSuperview().priority(.required)

        // replace this line
        //[=13=].top.bottom.greaterThanOrEqualToSuperview().inset(80.0)

        // with these two lines
        [=13=].top.greaterThanOrEqualToSuperview().offset(80.0)
        [=13=].bottom.lessThanOrEqualToSuperview().offset(-80.0)

        [=13=].leading.trailing.equalToSuperview().inset(16.0)
    }

变更前:

变更后:

关于在你有很多选项按钮时添加滚动,我可以给你一个滚动全部内容或滚动的例子] 选项按钮。