NSLayoutConstraints 在 UITableViewCell 中不受尊重
NSLayoutConstraints is not respected in UITableViewCell
我有一个 UITableViewCell
,一个 UILabel
和一个 UIImageView
。图像可以是可见的或隐藏的。
这是我的故事板:
UILabel
的尾部有两个约束,一个 (a) 等于 8 与 UIImageView
,另一个 (b) 大于或等于 8 与单元格的右边距。我保留第一个 (a) 的参考,如果有或没有声音,我会激活或停用约束。
这是我的代码:
class MyTableViewCell: UITableViewCell {
@IBOutlet weak var label: UILabel?
@IBOutlet weak var icon: UIImageView?
@IBOutlet weak var spaceBetweenIconAndLabelConstraint: NSLayoutConstraint?
override func awakeFromNib() {
super.awakeFromNib()
icon?.image = UIImage(named: "sound")
}
func config(with name: String, hasSound: Bool) {
label?.text = name
configSound(hasSound)
}
private func configSound(_ hasSound: Bool) {
icon?.isHidden = !hasSound
spaceBetweenIconAndLabelConstraint?.isActive = hasSound
}
}
我有几个单元格可以看到声音图标,很多没有。这是特定单元格首次出现时的样子:
以及它再次出现在屏幕上时的样子:
我知道问题出在重复使用的电池上。但我不明白如何防止这种行为。我尝试这样做:
override func prepareForReuse() {
configSound(true)
}
在重新使用单元格之前重新激活约束,但它不起作用。
我认为问题在于您对约束使用了 weak
引用。在这种情况下,一旦 isActive
属性 首次设置为 false
,约束就会被删除。从那以后它是 nil
并且不能被重新激活。
解决方案:通过删除 weak
关键字来使用强引用。
@IBOutlet var spaceBetweenIconAndLabelConstraint: NSLayoutConstraint!
有两种以上的方法可以做到。如果您的目标是 iOS 9+,我强烈建议您使用堆栈视图。它们完全满足您的需求,无需手动 add/remove/activate/deactivate 约束。
UI 看起来像这样:
stack view setup
水平堆栈视图(前导 8,尾随 8,间距等于 8)
里面:
1.在左边的标签上
2. 右侧图标图像视图(可选择包装在 iconContainer 视图中,或仅设置 aspectFit)
更新代码:
class MyTableViewCellWithStackView: UITableViewCell {
@IBOutlet weak var label: UILabel?
@IBOutlet weak var iconContainer: UIView?
func config(with name: String, hasSound: Bool) {
label?.text = name
iconContainer?.isHidden = !hasSound
}
}
每当您隐藏 icon/iconContainer 时,堆栈视图将自行更新并相应地填充 space。
如果你不能使用堆栈视图(首选),你可以试试这个:
class MyTableViewCell: UITableViewCell {
@IBOutlet weak var label: UILabel?
@IBOutlet weak var icon: UIImageView?
@IBOutlet weak var spaceBetweenIconAndLabelConstraint: NSLayoutConstraint?
override func awakeFromNib() {
super.awakeFromNib()
icon?.image = UIImage(named: "sound")
}
func config(with name: String, hasSound: Bool) {
label?.text = name
configSound(hasSound)
}
private func configSound(_ hasSound: Bool) {
icon?.isHidden = !hasSound
guard hasSound else {
spaceBetweenIconAndLabelConstraint?.isActive = false
return
}
guard let icon = icon, let label = label else { return }
let constraint = label.rightAnchor
.constraint(equalTo: icon.leftAnchor, constant: 8)
constraint.isActive = true
spaceBetweenIconAndLabelConstraint = constraint
}
}
我有一个 UITableViewCell
,一个 UILabel
和一个 UIImageView
。图像可以是可见的或隐藏的。
这是我的故事板:
UILabel
的尾部有两个约束,一个 (a) 等于 8 与 UIImageView
,另一个 (b) 大于或等于 8 与单元格的右边距。我保留第一个 (a) 的参考,如果有或没有声音,我会激活或停用约束。
这是我的代码:
class MyTableViewCell: UITableViewCell {
@IBOutlet weak var label: UILabel?
@IBOutlet weak var icon: UIImageView?
@IBOutlet weak var spaceBetweenIconAndLabelConstraint: NSLayoutConstraint?
override func awakeFromNib() {
super.awakeFromNib()
icon?.image = UIImage(named: "sound")
}
func config(with name: String, hasSound: Bool) {
label?.text = name
configSound(hasSound)
}
private func configSound(_ hasSound: Bool) {
icon?.isHidden = !hasSound
spaceBetweenIconAndLabelConstraint?.isActive = hasSound
}
}
我有几个单元格可以看到声音图标,很多没有。这是特定单元格首次出现时的样子:
以及它再次出现在屏幕上时的样子:
我知道问题出在重复使用的电池上。但我不明白如何防止这种行为。我尝试这样做:
override func prepareForReuse() {
configSound(true)
}
在重新使用单元格之前重新激活约束,但它不起作用。
我认为问题在于您对约束使用了 weak
引用。在这种情况下,一旦 isActive
属性 首次设置为 false
,约束就会被删除。从那以后它是 nil
并且不能被重新激活。
解决方案:通过删除 weak
关键字来使用强引用。
@IBOutlet var spaceBetweenIconAndLabelConstraint: NSLayoutConstraint!
有两种以上的方法可以做到。如果您的目标是 iOS 9+,我强烈建议您使用堆栈视图。它们完全满足您的需求,无需手动 add/remove/activate/deactivate 约束。
UI 看起来像这样:
stack view setup
水平堆栈视图(前导 8,尾随 8,间距等于 8) 里面: 1.在左边的标签上 2. 右侧图标图像视图(可选择包装在 iconContainer 视图中,或仅设置 aspectFit)
更新代码:
class MyTableViewCellWithStackView: UITableViewCell {
@IBOutlet weak var label: UILabel?
@IBOutlet weak var iconContainer: UIView?
func config(with name: String, hasSound: Bool) {
label?.text = name
iconContainer?.isHidden = !hasSound
}
}
每当您隐藏 icon/iconContainer 时,堆栈视图将自行更新并相应地填充 space。
如果你不能使用堆栈视图(首选),你可以试试这个:
class MyTableViewCell: UITableViewCell {
@IBOutlet weak var label: UILabel?
@IBOutlet weak var icon: UIImageView?
@IBOutlet weak var spaceBetweenIconAndLabelConstraint: NSLayoutConstraint?
override func awakeFromNib() {
super.awakeFromNib()
icon?.image = UIImage(named: "sound")
}
func config(with name: String, hasSound: Bool) {
label?.text = name
configSound(hasSound)
}
private func configSound(_ hasSound: Bool) {
icon?.isHidden = !hasSound
guard hasSound else {
spaceBetweenIconAndLabelConstraint?.isActive = false
return
}
guard let icon = icon, let label = label else { return }
let constraint = label.rightAnchor
.constraint(equalTo: icon.leftAnchor, constant: 8)
constraint.isActive = true
spaceBetweenIconAndLabelConstraint = constraint
}
}