UITableViewCell中不遵循NSLayoutConstraints

时间:2018-12-09 18:49:06

标签: ios swift uitableview nslayoutconstraint prepareforreuse

我有一个UITableViewCell和一个UILabel和一个UIImageView。图片可以显示或隐藏。

这是我的故事板: storyboard screenshot

UILabel的结尾部分有两个约束,一个约束(a)与UIImageView等于8,另一个约束(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
    }
}

我有几个带有可见声音图标的单元格,很多没有。这是特定单元格首次出现时的样子:

good behaviour

第二次返回屏幕时的外观:

bad behaviour

我确实知道问题出在重复使用的单元中。但是我不明白如何防止这种行为。我尝试这样做:

override func prepareForReuse() {
    configSound(true)
}

在重新使用单元格之前重新激活约束,但这不起作用。

2 个答案:

答案 0 :(得分:4)

我认为问题在于您使用weak引用作为约束。在这种情况下,约束第一次将其isActive属性设置为false时便被删除。由此可见nil,无法将其重新激活。

解决方案:删除关键字weak,以此作为强有力的参考。

@IBOutlet var spaceBetweenIconAndLabelConstraint: NSLayoutConstraint!

答案 1 :(得分:2)

有两种以上的方法可以做到这一点。如果您的目标是iOS 9+,则强烈建议您使用堆栈视图。它们完全可以满足您的需求,而无需手动添加/删除/激活/停用约束。

用户界面如下所示:

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,堆栈视图都会自动更新并相应地填充空间。

如果您不能使用堆栈视图(首选),可以尝试以下操作:

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
    }
}