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
    }
}
Другие вопросы по тегам