为啥我的第二个按钮在使用自动布局约束时表现不同?

Posted

技术标签:

【中文标题】为啥我的第二个按钮在使用自动布局约束时表现不同?【英文标题】:Why is my second button behaving different when using auto layout constraints?为什么我的第二个按钮在使用自动布局约束时表现不同? 【发布时间】:2020-07-02 11:21:48 【问题描述】:

我无法弄清楚为什么我的按钮在以编程方式使用自动布局约束时表现不同。

设置包含我的 cancelBtn 的视图时,一切正常:

 let cancelBtnView = TriangularView(frame: CGRect(x: 0, y: 0, width: 300, height: 150))

 let cancelBtn = UIButton()
 cancelBtnView.addSubview(cancelBtn)
 cancelBtn.titleLabel!.font = UIFont.fontAwesome(ofSize: 35, style: .regular)
 cancelBtn.setTitle(String.fontAwesomeIcon(name: .times), for: .normal)
 cancelBtn.frame = CGRect(x: cancelBtnView.bounds.width / 16, y: cancelBtnView.bounds.height / 2 ,width: 55, height: 55)

我得到以下布局:

为我的 doneBtn 设置视图时,我得到不同的输出:

let doneBtnView = TriangularView()

 doneBtnView.translatesAutoresizingMaskIntoConstraints = false
 doneBtnView.widthAnchor.constraint(equalToConstant: 300).isActive = true
 doneBtnView.heightAnchor.constraint(equalToConstant: 150).isActive = true
 doneBtnView.trailingAnchor.constraint(equalTo: actionButtonView.trailingAnchor).isActive = true
 doneBtnView.bottomAnchor.constraint(equalTo: actionButtonView.bottomAnchor).isActive = true

 let doneBtn = UIButton()
 doneBtnView.addSubview(doneBtn)
 doneBtn.titleLabel!.font = UIFont.fontAwesome(ofSize: 35, style: .regular)
 doneBtn.setTitle(String.fontAwesomeIcon(name: .check), for: .normal)

  doneBtn.translatesAutoresizingMaskIntoConstraints = false
  doneBtn.widthAnchor.constraint(equalToConstant: 55).isActive = true
  doneBtn.heightAnchor.constraint(equalToConstant: 55).isActive = true
  doneBtn.leadingAnchor.constraint(equalTo: doneBtnView.leadingAnchor, constant:    doneBtnView.bounds.width / 16).isActive = true
 doneBtn.bottomAnchor.constraint(equalTo: doneBtnView.bottomAnchor, constant: doneBtnView.bounds.height / 2).isActive = true

以编程方式为我的 doneBtn 设置约束我得到以下信息:

doneBtnView 的约束以编程方式设置,因为我想将其固定在其父视图的右下角。

【问题讨论】:

您的问题是,在为 doneBtn 设置约束时,您正在查看另一个视图的边界,但由于尚未发生布局,因此尚未设置这些边界。一般来说,结合框架/边界和约束是一个坏主意。您希望复选标记在哪里? 复选标记应与其他图标位于同一位置。或者更好的说法是:在三角形的中间。应该是: CGRect(x: doneBtnView.bounds.width / 16, y: doneBtnView.bounds.height / 2 ,width: 55, height: 55) 但这会将按钮放置在其顶部附近超级视图。 【参考方案1】:

您的问题是,在为 doneBtn 设置约束时,您正在查看另一个视图的边界,但这些边界尚未设置,因为尚未发生布局。一般来说,结合框架/边界和约束是个坏主意。

这可以做到,但不能使用锚点。试试下面的NSLayoutConstraints:

NSLayoutConstraint(item: doneBtn, attribute: .leading, relatedBy: .equal,
    toItem: doneBtnView, attribute: .trailing, multiplier: 1/16, constant: 0).isActive = true
    
NSLayoutConstraint(item: doneBtn, attribute: .top, relatedBy: .equal,
    toItem: doneBtnView, attribute: .bottom, multiplier: 1/2, constant: 0).isActive = true

然后使用锚点设置widthheight

doneBtn.widthAnchor.constraint(equalToConstant: 55).isActive = true
doneBtn.heightAnchor.constraint(equalToConstant: 55).isActive = true

注意:因为我们使用.trailing.bottom 约束来表示widthheight,所以可能需要将doneBtnView 放入容器视图中大小相同,因为值将位于父视图的坐标系中。通过使父视图的大小完全相同,宽度将等于尾部约束,高度将等于底部约束。

【讨论】:

在 Xcode 本身中查看 constraint(equalToConstant c: CGFloat) 的苹果文档时,它在讨论部分中说他们比较 使用 NSLayoutConstraint 创建约束... 使用 constraintEqualToConstant: 表示它们的行为相同。所以我认为使用这两种方法没有区别。 顺便说一句,您的代码运行良好,但文档让我感到困惑。 我正在创建在尾随和底部值上使用乘数的约束。锚点不允许您创建这些约束。 如果你设置一个常量约束,这个值将是固定的。如果您将其设置为相对于另一个视图的另一个特征,则当另一个视图更改时,将重新计算约束。我们需要改变它,因为在布置完 doneBtnView 之前,我们无法计算 checkMark 位置的实际值。

以上是关于为啥我的第二个按钮在使用自动布局约束时表现不同?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我的第二个视图在转换后没有加载?

当我添加自动布局约束时,为啥我的 textview 不显示?

以编程方式修改自动布局约束时视图不更新

为啥自动布局约束不起作用?

按钮单击在 Python 中的第二个类/布局中不起作用

是啥导致两个具有相同自动布局约束的 UITableViewCell 表现不同?