自动布局我可以将 CenterY 与顶部和底部约束结合起来吗?

Posted

技术标签:

【中文标题】自动布局我可以将 CenterY 与顶部和底部约束结合起来吗?【英文标题】:Autolayout Can I combine CenterY with Top and Bottom Constraints? 【发布时间】:2020-01-23 08:31:31 【问题描述】:

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

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

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

我心里已经有了一些想法,比如观察容器视图的高度是否超过设备高度。

我使用 snapKit,但限制应该是可以理解的。这是我目前的布局:

func setupUI() 

        self.view.backgroundColor = .clear

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

        self.view_BGFilter.snp.makeConstraints 
            $0.edges.equalToSuperview()
        

        self.view_Container.snp.makeConstraints 
            $0.centerY.equalToSuperview().priority(.high)
            //$0.top.bottom.greaterThanOrEqualToSuperview().inset(80.0).priority(.medium)
            $0.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 
            $0.top.equalToSuperview().inset(40.0)
            $0.leading.trailing.equalToSuperview().inset(16.0)
        

        self.stackView.snp.makeConstraints 
            $0.top.equalTo(self.label_Title.snp.bottom).offset(29.0)
            $0.leading.trailing.equalToSuperview().inset(24.0)
        

        self.button_Submit.snp.makeConstraints 
            $0.height.equalTo(52.0)
            $0.top.equalTo(self.stackView.snp.bottom).offset(30.0)
            $0.bottom.leading.trailing.equalToSuperview().inset(24.0)
        

        self.generateButtons()
    

【问题讨论】:

您是否希望选项按钮** 滚动(在需要时),将标题和确定按钮留在原处?还是您希望标题、选项按钮和 OKAAAAY 按钮全部滚动? 【参考方案1】:

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

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

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

在这种特定情况下,要么 SnapKit 存在一些错误,要么此特定行不太适合所需的结果:

$0.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 
            $0.centerY.equalToSuperview()

            // height exactly 200 points                
            $0.height.equalTo(200.0)

            // top and bottom at least 80 points from superview
            $0.top.bottom.greaterThanOrEqualToSuperview().inset(80.0)

            $0.leading.trailing.equalToSuperview().inset(16.0)
        

    


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

如果我们将该行替换如下:

        // replace this line
        //$0.top.bottom.greaterThanOrEqualToSuperview().inset(80.0)

        // with these two lines
        $0.top.greaterThanOrEqualToSuperview().offset(80.0)
        $0.bottom.lessThanOrEqualToSuperview().offset(-80.0)

当然似乎在做同样的事情,我们得到了我们所期望的:

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

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

    self.view_Container.snp.makeConstraints 
        $0.centerY.equalToSuperview().priority(.required)

        // replace this line
        //$0.top.bottom.greaterThanOrEqualToSuperview().inset(80.0)

        // with these two lines
        $0.top.greaterThanOrEqualToSuperview().offset(80.0)
        $0.bottom.lessThanOrEqualToSuperview().offset(-80.0)

        $0.leading.trailing.equalToSuperview().inset(16.0)
    

改动前:

改动后:

至于当您有许多选项按钮时添加滚动,我可以举一个例子,滚动所有内容或滚动选项按钮。

【讨论】:

不错的发现!非常感谢!

以上是关于自动布局我可以将 CenterY 与顶部和底部约束结合起来吗?的主要内容,如果未能解决你的问题,请参考以下文章

自动布局问题

自动布局在 centerX-centerY 上不起作用

自动布局不会减少顶部约束

与顶部布局指南和底部布局指南的距离相等

自动布局:隐藏工具栏后重置底部约束

如何使用自动布局约束在单个屏幕中放置两个视图