NSLayoutConstraints не соблюдается в UITableViewCell
У меня есть UITableViewCell
с UILabel
и UIImageView
, Изображение может быть видимым или скрытым.
Вот моя раскадровка:
Есть два ограничения на задней части UILabel
один (а), равный 8 с UIImageView
другой (b), который больше или равен 8 с правым полем ячейки. Я сохраняю ссылку на первый (а) и активирую или деактивирую ограничение, если есть или нет какой-то звук.
Вот мой код:
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)
}
повторно активировать ограничение перед повторным использованием ячейки, но это не работает.
2 ответа
Я думаю, что проблема в том, что вы используете weak
ссылка для вашего ограничения. В этом случае ограничение снимается, как только его isActive
свойство установлено в false
в первый раз. С этого момента это nil
и не может быть реактивирован.
Решение: используйте надежную ссылку, удалив weak
ключевое слово.
@IBOutlet var spaceBetweenIconAndLabelConstraint: NSLayoutConstraint!
Есть более двух способов сделать это. Если вы ориентируетесь на iOS 9+, я настоятельно рекомендую использовать стековые представления. Они делают именно то, что вам нужно, без необходимости вручную добавлять / удалять / активировать / деактивировать ограничения.
Пользовательский интерфейс будет выглядеть так:
Горизонтальный вид стека (от 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, представление стека обновляется и соответственно заполняет пространство.
Если вы не можете использовать представления стека (предпочтительно), вы можете попробовать это:
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
}
}