UITableViewCell скрывает часть содержимого после появления на экране с пользовательским layoutSubviews () - PullRequest
3 голосов
/ 16 марта 2019

Я борюсь с UITableView. Как вы можете видеть в это видео в третьем разделе табличного представления, третья ячейка отображается неправильно. Это происходит, когда я снимаю свою клетку вот так:

let cell = tableView.dequeueReusableCell(withIdentifier: MultipleSelectAnswerSurveyTableViewCellIdentifier, for: indexPath) as! MultipleSelectAnswerSurveyTableViewCell
cell.setup(answer: question.answers?[indexPath.row].value ?? "", isSelected: false, style: style, isLastInSection: indexPath.row == (question.answers?.count ?? 1) - 1)
return cell

Метод ячейки setup():

func setup(answer: String, isSelected: Bool, style: Style, isLastInSection: Bool) {
    self.isLastInSection = isLastInSection
    selectionStyle = .none
    backgroundColor = style.survey.singleSelectAnswerTableViewCell.backgroundColor
    answerLabel.textColor = style.survey.singleSelectAnswerTableViewCell.answerLabelColor
    answerLabel.font = style.survey.singleSelectAnswerTableViewCell.answerLabelFont
    answerLabel.text = answer
    addSubview(answerLabel)
    addSubview(selectionIndicator)
    answerLabel.snp.makeConstraints { make in
        make.left.equalTo(8)
        make.centerY.equalTo(selectionIndicator.snp.centerY)
        make.top.equalTo(8)
        make.bottom.equalTo(-8)
        make.right.equalTo(selectionIndicator.snp.left).offset(-8)
    }
    selectionIndicator.snp.makeConstraints { make in
        make.right.equalTo(-8)
        make.top.greaterThanOrEqualTo(8)
        make.bottom.lessThanOrEqualTo(-8)
        make.width.height.equalTo(26)
    }
}

self.isLastInSection переменная используется внутри layoutSubviews():

override func layoutSubviews() {
    super.layoutSubviews()
    if isLastInSection {
        roundCorners(corners: [.bottomLeft, .bottomRight], radius: 16.0)
    }
    contentView.layoutIfNeeded()
}

И, наконец, roundCorners():

extension UIView {
    func roundCorners(corners: UIRectCorner, radius: CGFloat) {
        let path = UIBezierPath(roundedRect: bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
        let mask = CAShapeLayer()
        mask.path = path.cgPath
        layer.mask = mask
    }
}

Когда я снимаю ячейку с isLastInSection, установленным на ложную ячейку, отображается, как и ожидалось ( видео ). Поэтому я думаю, что проблема в жизненном цикле клетки и когда вызывается layoutSubview(). Я перепробовал много решений для похожих проблем, найденных в разных темах, но ни одно из них не помогло мне. tableView(_:heightForRowAt:) заставляет третью ячейку отображаться правильно, но первая имеет закругленные нижние углы. Также все они зафиксированы по высоте, и этого не может быть. Но что действительно странно: когда я печатаю isLastInSection во время удаления очереди из ячейки, которая неожиданно округляется, отладчик возвращает мне значение false:

(lldb) po indexPath.row == (question.answers?.count ?? 1) - 1 false

enter image description here

Как вы можете видеть в Debug View Hierarchy, текст представления существует, поэтому я определил проблему как скрывающую часть содержимого.

Debug View hierarchy

1 Ответ

1 голос
/ 16 марта 2019

Вы удаляете ячейку из очереди и каждый раз, когда вы добавляете подпредставления, вы не проверяете, есть ли они там, что произойдет в случае переработанной ячейки. Это, вероятно, нарушает ограничения и вызывает неправильный размер.

Та же проблема с округлением - вы устанавливаете закругленные углы, но вы никогда не отмените это поведение, когда повторно используемая ячейка не должна быть округлена.

Лучший способ решить эту проблему - добавить дополнительную проверку и создать подпредставления только один раз:

func setup(answer: String, isSelected: Bool, style: Style, isLastInSection: Bool) {
    if self.subviews.count == 0 {
        // adding subviews etc.
        // code that needs to be performed only once for whole cell's life
    }

    self.isLastInSection = isLastInSection
    // set up content that changes for each cell (like text)
    // for example a code depending on parameters of this method
}

в качестве альтернативы вы можете оставить какое-то свойство, например isInitialized, и проверить это в начале.

Также ваш метод layoutSubviews должен поддерживать оба случая:

override func layoutSubviews() {
    super.layoutSubviews()
    if isLastInSection {
        roundCorners(corners: [.bottomLeft, .bottomRight], radius: 16.0)
    } else {
        layer.mask = nil
    }
    contentView.layoutIfNeeded()
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...