如何动态更新约束?
How to update constraints dynamically?
我有三个 UIButton
,我以编程方式创建了约束,在某些情况下我将删除 UIButton
中的一个作为 button.removeFromSuperview()
,其余两个按钮将根据优先级设置约束.
问题是当我删除一个 UIButton
(buttonWink) 时,从 viewLifeCycle viewWillLayoutSubviews
开始,将在下面的行
中调用应用程序崩溃
buttonWink.translatesAutoresizingMaskIntoConstraints = false
当然,因为 buttonWink 已从 superview 中删除,但是我们可以在将约束设置为
之前进行检查
if buttonWink != nil {
buttonWink.translatesAutoresizingMaskIntoConstraints = false
}
但是为每个按钮检查 nil 会使代码冗长,有什么办法可以做到这一点吗?我会非常感谢朋友。
输出 -
在此附上我尝试过的完整代码。
import UIKit
class MasterViewController: UIViewController {
@IBOutlet weak var buttonMessage : UIButton!
@IBOutlet weak var buttonLike : UIButton!
@IBOutlet weak var buttonWink : UIButton!
@IBAction func tapsOnLike(_ sender: UIButton) {
sender.removeFromSuperview()
}
@IBAction func tapsOnWink(_ sender: UIButton) {
sender.removeFromSuperview()
}
@IBAction func tapsOnNextButton(){
let vc = DetailViewController(nibName: "DetailViewController", bundle: nil)
navigationController?.pushViewController(vc, animated: true)
}
override func viewDidLoad() {
super.viewDidLoad()
setConstraints()
navigationController?.isNavigationBarHidden = true
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(true)
// setConstraints()
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
//setConstraints()
}
func setConstraints() {
if buttonMessage != nil {
buttonMessage?.translatesAutoresizingMaskIntoConstraints = false
}
buttonLike?.translatesAutoresizingMaskIntoConstraints = false
buttonWink?.translatesAutoresizingMaskIntoConstraints = false
//Constraints for Message button
let leading = NSLayoutConstraint(item: buttonMessage, attribute: .leading, relatedBy: .equal, toItem: view, attribute: .leading, multiplier: 1.0, constant: 8)
leading.isActive = true
let trailingToSuperView = NSLayoutConstraint(item: buttonMessage, attribute: .trailing, relatedBy: .equal, toItem: view, attribute: .trailing, multiplier: 1, constant: -8)
trailingToSuperView.priority = 998
trailingToSuperView.isActive = true
let bottomToSuperView = NSLayoutConstraint(item: buttonMessage, attribute: .bottom, relatedBy: .equal, toItem: view, attribute: .bottom, multiplier: 1, constant: -8)
bottomToSuperView.isActive = true
let trailingToWink = NSLayoutConstraint(item: buttonMessage, attribute: .trailing, relatedBy: .equal, toItem: buttonWink, attribute: .leading, multiplier: 1, constant: -8)
trailingToWink.priority = 999
trailingToWink.isActive = true
let leadingToLike = NSLayoutConstraint(item: buttonMessage, attribute: .trailing, relatedBy: .equal, toItem: buttonLike, attribute: .leading, multiplier: 1.0, constant: -8)
leadingToLike.isActive = true
let alignBottomToWink = NSLayoutConstraint(item: buttonMessage, attribute: .bottom, relatedBy: .equal, toItem: buttonWink, attribute: .bottom, multiplier: 1, constant: 0)
alignBottomToWink.isActive = true
let alignBottomToLike = NSLayoutConstraint(item: buttonMessage, attribute: .bottom, relatedBy: .equal, toItem: buttonLike, attribute: .bottom, multiplier: 1, constant: 0)
alignBottomToLike.isActive = true
let equalWidthToWink = NSLayoutConstraint(item: buttonMessage, attribute: .width, relatedBy: .equal, toItem: buttonWink, attribute: .width, multiplier: 1, constant: 0)
equalWidthToWink.isActive = true
let equalWidthToLike = NSLayoutConstraint(item: buttonMessage, attribute: .width, relatedBy: .equal, toItem: buttonLike, attribute: .width, multiplier: 1, constant: 0)
equalWidthToLike.isActive = true
//Constraints for like button
let trailingLikeToSuperView = NSLayoutConstraint(item: buttonLike, attribute: .trailing, relatedBy: .equal, toItem: view, attribute: .trailing, multiplier: 1, constant: -8)
trailingLikeToSuperView.priority = 999
trailingLikeToSuperView.isActive = true
let leadingToWink = NSLayoutConstraint(item: buttonLike, attribute: .trailing, relatedBy: .equal, toItem: buttonWink, attribute: .leading, multiplier: 1.0, constant: -8)
leadingToWink.isActive = true
//Constraints for Wink button
let trailingWinkToSuperView = NSLayoutConstraint(item: buttonWink, attribute: .trailing, relatedBy: .equal, toItem: view, attribute: .trailing, multiplier: 1, constant: -8)
trailingWinkToSuperView.isActive = true
}
}
就您的 viewWillLayoutSubviews
代码而言,将您的按钮放入数组中以供使用:
for btn in buttons {
if (btn.superview != nil) {
btn.translatesAutoresizingMaskIntoConstraints = false
}
}
如果您想更改仍在视图中的按钮的约束,请在创建约束时为它们提供标识符:
for btn in buttons {
if btn.superview != nil {
btn.translatesAutoresizingMaskIntoConstraints = false
for constraint in btn.constraints {
switch constraint.identifier {
case "winkBtnTrailing":
//do stuff like constraint = new layout constraint
//or constraint.firstItem = *new first Item to base trailing on*
break
default:
//don't do stuff?
break
}
}
}
}
正如使用 button.removeFromSuperview()
的 FYI 不会将该按钮设置为 nil,它只是将其从您在
上调用 .addSubview(button)
的视图中删除
仅供参考 -
为此简单地使用堆栈视图。
这非常简单:这就是 Apple 在几年前终于添加堆栈概念的原因。
我刚刚添加了 UIStackView
& 这太简单了,
在水平堆栈视图中添加了三个按钮,间距为 8 点,并向堆栈视图添加了三个约束,如 leading
、trailing
和 bottom
到 superview
@IBOutlet weak var stackView: UIStackView!
@IBAction func tapsOnLikeInStack(_ sender: UIButton) {
sender.isHidden = true
}
@IBAction func tapsOnWinkInStack(_ sender: UIButton) {
sender.isHidden = true
}
func constraintsForStackView(){
stackView?.translatesAutoresizingMaskIntoConstraints = false
stackView.spacing = 8
stackView.axis = .horizontal
stackView.distribution = .fillEqually
stackView.alignment = .fill
let leading = NSLayoutConstraint(item: stackView, attribute: .leading, relatedBy: .equal, toItem: view, attribute: .leading, multiplier: 1.0, constant: 8)
leading.isActive = true
let trailingToSuperView = NSLayoutConstraint(item: stackView, attribute: .trailing, relatedBy: .equal, toItem: view, attribute: .trailing, multiplier: 1, constant: -8)
trailingToSuperView.isActive = true
let bottomToSuperView = NSLayoutConstraint(item: stackView, attribute: .bottom, relatedBy: .equal, toItem: view, attribute: .bottom, multiplier: 1, constant: -120)
bottomToSuperView.isActive = true
}
我有三个 UIButton
,我以编程方式创建了约束,在某些情况下我将删除 UIButton
中的一个作为 button.removeFromSuperview()
,其余两个按钮将根据优先级设置约束.
问题是当我删除一个 UIButton
(buttonWink) 时,从 viewLifeCycle viewWillLayoutSubviews
开始,将在下面的行
buttonWink.translatesAutoresizingMaskIntoConstraints = false
当然,因为 buttonWink 已从 superview 中删除,但是我们可以在将约束设置为
之前进行检查 if buttonWink != nil {
buttonWink.translatesAutoresizingMaskIntoConstraints = false
}
但是为每个按钮检查 nil 会使代码冗长,有什么办法可以做到这一点吗?我会非常感谢朋友。
输出 -
在此附上我尝试过的完整代码。
import UIKit
class MasterViewController: UIViewController {
@IBOutlet weak var buttonMessage : UIButton!
@IBOutlet weak var buttonLike : UIButton!
@IBOutlet weak var buttonWink : UIButton!
@IBAction func tapsOnLike(_ sender: UIButton) {
sender.removeFromSuperview()
}
@IBAction func tapsOnWink(_ sender: UIButton) {
sender.removeFromSuperview()
}
@IBAction func tapsOnNextButton(){
let vc = DetailViewController(nibName: "DetailViewController", bundle: nil)
navigationController?.pushViewController(vc, animated: true)
}
override func viewDidLoad() {
super.viewDidLoad()
setConstraints()
navigationController?.isNavigationBarHidden = true
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(true)
// setConstraints()
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
//setConstraints()
}
func setConstraints() {
if buttonMessage != nil {
buttonMessage?.translatesAutoresizingMaskIntoConstraints = false
}
buttonLike?.translatesAutoresizingMaskIntoConstraints = false
buttonWink?.translatesAutoresizingMaskIntoConstraints = false
//Constraints for Message button
let leading = NSLayoutConstraint(item: buttonMessage, attribute: .leading, relatedBy: .equal, toItem: view, attribute: .leading, multiplier: 1.0, constant: 8)
leading.isActive = true
let trailingToSuperView = NSLayoutConstraint(item: buttonMessage, attribute: .trailing, relatedBy: .equal, toItem: view, attribute: .trailing, multiplier: 1, constant: -8)
trailingToSuperView.priority = 998
trailingToSuperView.isActive = true
let bottomToSuperView = NSLayoutConstraint(item: buttonMessage, attribute: .bottom, relatedBy: .equal, toItem: view, attribute: .bottom, multiplier: 1, constant: -8)
bottomToSuperView.isActive = true
let trailingToWink = NSLayoutConstraint(item: buttonMessage, attribute: .trailing, relatedBy: .equal, toItem: buttonWink, attribute: .leading, multiplier: 1, constant: -8)
trailingToWink.priority = 999
trailingToWink.isActive = true
let leadingToLike = NSLayoutConstraint(item: buttonMessage, attribute: .trailing, relatedBy: .equal, toItem: buttonLike, attribute: .leading, multiplier: 1.0, constant: -8)
leadingToLike.isActive = true
let alignBottomToWink = NSLayoutConstraint(item: buttonMessage, attribute: .bottom, relatedBy: .equal, toItem: buttonWink, attribute: .bottom, multiplier: 1, constant: 0)
alignBottomToWink.isActive = true
let alignBottomToLike = NSLayoutConstraint(item: buttonMessage, attribute: .bottom, relatedBy: .equal, toItem: buttonLike, attribute: .bottom, multiplier: 1, constant: 0)
alignBottomToLike.isActive = true
let equalWidthToWink = NSLayoutConstraint(item: buttonMessage, attribute: .width, relatedBy: .equal, toItem: buttonWink, attribute: .width, multiplier: 1, constant: 0)
equalWidthToWink.isActive = true
let equalWidthToLike = NSLayoutConstraint(item: buttonMessage, attribute: .width, relatedBy: .equal, toItem: buttonLike, attribute: .width, multiplier: 1, constant: 0)
equalWidthToLike.isActive = true
//Constraints for like button
let trailingLikeToSuperView = NSLayoutConstraint(item: buttonLike, attribute: .trailing, relatedBy: .equal, toItem: view, attribute: .trailing, multiplier: 1, constant: -8)
trailingLikeToSuperView.priority = 999
trailingLikeToSuperView.isActive = true
let leadingToWink = NSLayoutConstraint(item: buttonLike, attribute: .trailing, relatedBy: .equal, toItem: buttonWink, attribute: .leading, multiplier: 1.0, constant: -8)
leadingToWink.isActive = true
//Constraints for Wink button
let trailingWinkToSuperView = NSLayoutConstraint(item: buttonWink, attribute: .trailing, relatedBy: .equal, toItem: view, attribute: .trailing, multiplier: 1, constant: -8)
trailingWinkToSuperView.isActive = true
}
}
就您的 viewWillLayoutSubviews
代码而言,将您的按钮放入数组中以供使用:
for btn in buttons {
if (btn.superview != nil) {
btn.translatesAutoresizingMaskIntoConstraints = false
}
}
如果您想更改仍在视图中的按钮的约束,请在创建约束时为它们提供标识符:
for btn in buttons {
if btn.superview != nil {
btn.translatesAutoresizingMaskIntoConstraints = false
for constraint in btn.constraints {
switch constraint.identifier {
case "winkBtnTrailing":
//do stuff like constraint = new layout constraint
//or constraint.firstItem = *new first Item to base trailing on*
break
default:
//don't do stuff?
break
}
}
}
}
正如使用 button.removeFromSuperview()
的 FYI 不会将该按钮设置为 nil,它只是将其从您在
.addSubview(button)
的视图中删除
仅供参考 -
为此简单地使用堆栈视图。
这非常简单:这就是 Apple 在几年前终于添加堆栈概念的原因。
我刚刚添加了 UIStackView
& 这太简单了,
在水平堆栈视图中添加了三个按钮,间距为 8 点,并向堆栈视图添加了三个约束,如 leading
、trailing
和 bottom
到 superview
@IBOutlet weak var stackView: UIStackView!
@IBAction func tapsOnLikeInStack(_ sender: UIButton) {
sender.isHidden = true
}
@IBAction func tapsOnWinkInStack(_ sender: UIButton) {
sender.isHidden = true
}
func constraintsForStackView(){
stackView?.translatesAutoresizingMaskIntoConstraints = false
stackView.spacing = 8
stackView.axis = .horizontal
stackView.distribution = .fillEqually
stackView.alignment = .fill
let leading = NSLayoutConstraint(item: stackView, attribute: .leading, relatedBy: .equal, toItem: view, attribute: .leading, multiplier: 1.0, constant: 8)
leading.isActive = true
let trailingToSuperView = NSLayoutConstraint(item: stackView, attribute: .trailing, relatedBy: .equal, toItem: view, attribute: .trailing, multiplier: 1, constant: -8)
trailingToSuperView.isActive = true
let bottomToSuperView = NSLayoutConstraint(item: stackView, attribute: .bottom, relatedBy: .equal, toItem: view, attribute: .bottom, multiplier: 1, constant: -120)
bottomToSuperView.isActive = true
}