修改UIButton图片后如何更新约束?调用原有约束方法出现冲突如何解决
问题成因
每次调用setupConstraints()函数时,NSLayoutConstraint.activate只会新增并激活约束,不会自动删除旧的同属性约束。首次初始化布局时没有历史约束因此运行正常,后续更新国旗再次调用该函数时,每个按钮的宽度约束会重复添加,不同宽高比的约束同时激活就会触发冲突,就是你日志里看到的同一个按钮存在两个不同乘数的宽度约束的报错。
你当前每次更新就全量重加所有约束的方案不合理,固定不变的位置、高度类约束不需要重复添加,只会带来额外的性能开销和冲突风险。
最优解决方案
只更新需要变动的宽度约束即可,固定约束仅在页面初始化时添加一次:
- 首先在ViewController中声明三个按钮的宽度约束为全局属性
// 存储三个按钮的宽度约束 var firstBtnWidthConstraint: NSLayoutConstraint! var secondBtnWidthConstraint: NSLayoutConstraint! var thirdBtnWidthConstraint: NSLayoutConstraint!
- 在viewDidLoad中调用一次固定约束初始化方法,只添加不变的约束
func setupStaticConstraints() { NSLayoutConstraint.activate([ countryNameLabel.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 10), countryNameLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor), countryNameLabel.widthAnchor.constraint(equalTo: view.widthAnchor, constant: -20), countryNameLabel.heightAnchor.constraint(equalToConstant: 30), firstCountryButton.topAnchor.constraint(equalTo: countryNameLabel.bottomAnchor, constant: 35), firstCountryButton.centerXAnchor.constraint(equalTo: view.centerXAnchor), firstCountryButton.heightAnchor.constraint(equalToConstant: 120), secondCountryButton.topAnchor.constraint(equalTo: firstCountryButton.bottomAnchor, constant: 25), secondCountryButton.centerXAnchor.constraint(equalTo: view.centerXAnchor), secondCountryButton.heightAnchor.constraint(equalToConstant: 120), thirdCountryButton.topAnchor.constraint(equalTo: secondCountryButton.bottomAnchor, constant: 25), thirdCountryButton.centerXAnchor.constraint(equalTo: view.centerXAnchor), thirdCountryButton.heightAnchor.constraint(equalToConstant: 120), ]) // 初始化首次的宽度约束 firstBtnWidthConstraint = firstCountryButton.widthAnchor.constraint(equalTo: firstCountryButton.heightAnchor, multiplier: flagImages[0].getAspectRatio()) secondBtnWidthConstraint = secondCountryButton.widthAnchor.constraint(equalTo: secondCountryButton.heightAnchor, multiplier: flagImages[1].getAspectRatio()) thirdBtnWidthConstraint = thirdCountryButton.widthAnchor.constraint(equalTo: thirdCountryButton.heightAnchor, multiplier: flagImages[2].getAspectRatio()) [firstBtnWidthConstraint, secondBtnWidthConstraint, thirdBtnWidthConstraint].forEach { $0.isActive = true } }
- 每次更新国旗时,仅更新宽度约束即可
func updateFlagWidthConstraints() { // 停用旧的宽度约束 firstBtnWidthConstraint.isActive = false secondBtnWidthConstraint.isActive = false thirdBtnWidthConstraint.isActive = false // 生成新的宽度约束 firstBtnWidthConstraint = firstCountryButton.widthAnchor.constraint(equalTo: firstCountryButton.heightAnchor, multiplier: flagImages[0].getAspectRatio()) secondBtnWidthConstraint = secondCountryButton.widthAnchor.constraint(equalTo: secondCountryButton.heightAnchor, multiplier: flagImages[1].getAspectRatio()) thirdBtnWidthConstraint = thirdCountryButton.widthAnchor.constraint(equalTo: thirdCountryButton.heightAnchor, multiplier: flagImages[2].getAspectRatio()) // 激活新约束并触发布局更新 [firstBtnWidthConstraint, secondBtnWidthConstraint, thirdBtnWidthConstraint].forEach { $0.isActive = true } view.layoutIfNeeded() }
快速修改方案(适合临时调整)
如果不想大幅改动原有代码,可以在每次调用setupConstraints()之前,先移除所有旧约束,再激活新约束:
// 调用setupConstraints前先执行 view.constraints.forEach { $0.isActive = false } setupConstraints()
该方案实现简单但性能较差,会全量删除重建所有约束,仅适合小型页面使用。
内容的提问来源于stack exchange,提问作者adseeAnn
相关产品推荐
相关产品推荐

