UITableViewCell не использует высоту автоматического размещения при использовании вставки ячейки в таблицу - PullRequest
0 голосов
/ 04 декабря 2018

Фон

Я использую purelayout для программного создания моих UITableViewCells, следуя инструкциям здесь , в которых в основном говорится, что вы должны установить ограничения сверху / снизу для ячейки, а затем использовать

self.tableView.rowHeight = UITableViewAutomaticDimension;

чтобы понять это правильно:

enter image description here

Проблема

Все работает отлично, кроме случаев, когда я вставляю новыйстрока в табличном представлении.Я получаю этот эффект: https://youtu.be/eTGWsxwDAdk

Объяснить: как только я нажму на одну из ячеек подсказок, в таблицу будет вставлена ​​строка подсказка драйвера .Тем не менее, вы заметите, что когда я обновляю раздел (нажимая на подсказку), высота всех ячеек необъяснимым образом увеличивается, но когда я снова нажимаю на подсказки, они возвращаются к своей нормальной высоте, что делается с помощью этого кода

self.tableView.beginUpdates()
self.tableView.reloadSections(IndexSet(integer:1), with: .automatic)
self.tableView.endUpdates()

это реализация ячейки для строки

// init table
self.tableView.register(OrderChargeTableViewCell.self,
                            forCellReuseIdentifier: OrderChargeTableViewCell.regularCellIdentifier)
self.tableView.register(OrderChargeTableViewCell.self,
                            forCellReuseIdentifier: OrderChargeTableViewCell.boldCellIdentifier)

self.tableView.estimatedRowHeight = 25
self.tableView.rowHeight = UITableViewAutomaticDimension

public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    var cell: OrderChargeTableViewCell?
    if (indexPath.row == filteredModel.count-1) {
        cell = tableView.dequeueReusableCell(withIdentifier: OrderChargeTableViewCell.boldCellIdentifier,
                                             for: indexPath) as? OrderChargeTableViewCell
    } else if (indexPath.row < filteredModel.count) {
        cell = tableView.dequeueReusableCell(withIdentifier: OrderChargeTableViewCell.regularCellIdentifier,
                                             for: indexPath) as? OrderChargeTableViewCell
    }

    // add data to cell labels
    return cell!
}

, и это код самого UITableViewCell:

конечный класс OrderChargeTableViewCell: UITableViewCell {

// MARK: - init
static let boldCellIdentifier = "TTOrderDetailBoldTableViewCell"
static let regularCellIdentifier = "TTOrderDetailRegularTableViewCell"

private var didSetupConstraints = false
.. 

override init(style: UITableViewCellStyle, reuseIdentifier: String?) {

    self.keyLabel = TTRLabel()
    self.valueLabel = TTRLabel()

    if (reuseIdentifier == OrderChargeTableViewCell.regularCellIdentifier) {
        self.isCellStyleBold = false
    } else if (reuseIdentifier == OrderChargeTableViewCell.boldCellIdentifier) {
        self.isCellStyleBold = true
    } else {
        self.isCellStyleBold = false
        assertionFailure( "Attempt to create an OrderCharge cell with the wrong cell identifier: \(String(describing: reuseIdentifier))")
    }

    super.init(style: style, reuseIdentifier: reuseIdentifier)


    contentView.addSubview(keyLabel)
    contentView.addSubview(valueLabel)

}

override func updateConstraints()
{
    if !didSetupConstraints {
        if (isCellStyleBold) {
            self.applyBoldFormatting()
        } else {
            self.applyRegularFormatting()
        }

        didSetupConstraints = true
    }

    super.updateConstraints()
}
public func applyBoldFormatting() {
    keyLabel.font = .ttrSubTitle
    valueLabel.font = .ttrBody

    keyLabel.autoPinEdge(.leading, to: .leading, of: contentView, withOffset: 15)
    keyLabel.autoAlignAxis(.vertical, toSameAxisOf: contentView)

    keyLabel.autoPinEdge(.top, to: .top, of: contentView, withOffset: 8)
    keyLabel.autoPinEdge(.bottom, to: .bottom, of: contentView, withOffset: -8)

    valueLabel.autoPinEdge(.trailing, to: .trailing, of: contentView, withOffset: -15)
    valueLabel.autoAlignAxis(.baseline, toSameAxisOf: keyLabel)
}

public func applyRegularFormatting() {
    keyLabel.font = .ttrCaptions
    valueLabel.font = TTRFont.Style.standard(.h3).value

    keyLabel.autoPinEdge(.leading, to: .leading, of: contentView, withOffset: 15)
    keyLabel.autoAlignAxis(.vertical, toSameAxisOf: contentView)

    keyLabel.autoPinEdge(.top, to: .top, of: contentView, withOffset: 6)
    keyLabel.autoPinEdge(.bottom, to: .bottom, of: contentView, withOffset: -4)

    valueLabel.autoPinEdge(.trailing, to: .trailing, of: contentView, withOffset: -15)
    valueLabel.autoAlignAxis(.baseline, toSameAxisOf: keyLabel)
}

строка вставляемого наконечника драйвера имеет стандартную высоту ячейки 44 пикселя: enter image description here

, тогда как остальные (правильно отформатированные) ячейки имеют высоту 25: enter image description here

Ответы [ 2 ]

0 голосов
/ 05 декабря 2018

Несмотря на то, что за ответом StackOverflow, за которым вы следовали, много голосов, похоже, вы взяли один пункт, который был не очень хорошо объяснен (и может быть устаревшим), и я думаю, что это может быть причиной ваших проблем.

Вы найдете много комментариев / сообщений / статей, в которых говорится, что вы должны добавить свои ограничения в updateConstraints(), однако Документы Apple также указывают:

Переопределите этот методоптимизировать изменения в ваших ограничениях.

Примечание

Почти всегда проще и проще обновлять ограничение сразу после того, как произошло изменение.Например, если вы хотите изменить ограничение в ответ на нажатие кнопки, сделайте это изменение непосредственно в методе действия кнопки.

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

Я думаю, что вы получите гораздо лучшие результаты в своих попытках, если добавите свои подпредставления и их ограничения, когда ваша ячейка инициализирована.

Вот простой пример, который имеет макет, подобный тому, что вы показали.Он создает таблицу с 2 разделами - первый раздел имеет строку с кнопкой «показать / скрыть».При нажатии второй раздел добавляет / удаляет строку «Driver Tip».

//
//  InsertRemoveViewController.swift
//
//  Created by Don Mag on 12/4/18.
//

import UIKit

struct MyRowData {
    var title: String = ""
    var value: CGFloat = 0.0
}

class OrderChargeTableViewCell: UITableViewCell {

    static let boldCellIdentifier: String = "TTOrderDetailBoldTableViewCell"
    static let regularCellIdentifier: String = "TTOrderDetailRegularTableViewCell"

    var keyLabel: UILabel = {
        let v = UILabel()
        v.translatesAutoresizingMaskIntoConstraints = false
        return v
    }()

    var valueLabel: UILabel = {
        let v = UILabel()
        v.translatesAutoresizingMaskIntoConstraints = false
        return v
    }()

    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        commonInit()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        commonInit()
    }

    func commonInit() -> Void {

        contentView.addSubview(keyLabel)
        contentView.addSubview(valueLabel)

        let s = type(of: self).boldCellIdentifier

        if self.reuseIdentifier == s {

            NSLayoutConstraint.activate([
                keyLabel.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 8.0),
                keyLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -8.0),
                keyLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 15.0),

                valueLabel.centerYAnchor.constraint(equalTo: keyLabel.centerYAnchor, constant: 0.0),
                valueLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -15.0),
                ])

            keyLabel.font = UIFont.systemFont(ofSize: 15, weight: .bold)
            valueLabel.font = UIFont.systemFont(ofSize: 15, weight: .bold)

        } else {

            NSLayoutConstraint.activate([
                keyLabel.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 6.0),
                keyLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -4.0),
                keyLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 15.0),

                valueLabel.centerYAnchor.constraint(equalTo: keyLabel.centerYAnchor, constant: 0.0),
                valueLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -15.0),
                ])

            keyLabel.font = UIFont.systemFont(ofSize: 12, weight: .bold)
            valueLabel.font = UIFont.systemFont(ofSize: 12, weight: .regular)

        }

    }

}

class TipCell: UITableViewCell {

    var callBack: (() -> ())?

    var theButton: UIButton = {
        let b = UIButton()
        b.translatesAutoresizingMaskIntoConstraints = false
        b.setTitle("Tap to Show/Hide Add Tip row", for: .normal)
        b.setTitleColor(.blue, for: .normal)
        b.backgroundColor = .yellow
        return b
    }()

    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        commonInit()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        commonInit()
    }

    func commonInit() -> Void {

        contentView.addSubview(theButton)

        NSLayoutConstraint.activate([
            theButton.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 20.0),
            theButton.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -20.0),
            theButton.centerXAnchor.constraint(equalTo: contentView.centerXAnchor, constant: 0.0),
            ])

        theButton.addTarget(self, action: #selector(btnTapped(_:)), for: .touchUpInside)

    }

    @objc func btnTapped(_ sender: Any?) -> Void {
        callBack?()
    }

}

class InsertRemoveViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

    var myData = [
        MyRowData(title: "SUBTOTAL", value: 4),
        MyRowData(title: "DELIVERY CHARGE", value: 1.99),
        MyRowData(title: "DISCOUNT", value: -1.99),
        MyRowData(title: "TOTAL", value: 4),
        ]

    var tableView: UITableView = {
        let v = UITableView()
        v.translatesAutoresizingMaskIntoConstraints = false
        return v
    }()


    func tipRowShowHide() {

        let iPath = IndexPath(row: 3, section: 1)

        if myData.count == 4 {
            myData.insert(MyRowData(title: "DRIVER TIP", value: 2.0), at: 3)
            tableView.insertRows(at: [iPath], with: .automatic)
        } else {
            myData.remove(at: 3)
            tableView.deleteRows(at: [iPath], with: .automatic)
        }

    }

    override func viewDidLoad() {
        super.viewDidLoad()

        tableView.register(OrderChargeTableViewCell.self,
                           forCellReuseIdentifier: OrderChargeTableViewCell.regularCellIdentifier)
        tableView.register(OrderChargeTableViewCell.self,
                           forCellReuseIdentifier: OrderChargeTableViewCell.boldCellIdentifier)

        tableView.register(TipCell.self, forCellReuseIdentifier: "TipCell")

        tableView.delegate = self
        tableView.dataSource = self

        tableView.rowHeight = UITableViewAutomaticDimension
        tableView.estimatedRowHeight = 25

        view.backgroundColor = .red

        view.addSubview(tableView)

        NSLayoutConstraint.activate([
            tableView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 200.0),
            tableView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -20.0),
            tableView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 20.0),
            tableView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -20.0),
            ])

    }

    func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return " "
    }

    func numberOfSections(in tableView: UITableView) -> Int {
        return 2
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return section == 0 ? 1 : myData.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        if indexPath.section == 0 {

            let cell = tableView.dequeueReusableCell(withIdentifier: "TipCell", for: indexPath) as! TipCell

            cell.callBack = {
                self.tipRowShowHide()
            }

            return cell

        }

        var cell: OrderChargeTableViewCell?

        if indexPath.row == myData.count - 1 {

            cell = tableView.dequeueReusableCell(withIdentifier: OrderChargeTableViewCell.boldCellIdentifier,
                                                 for: indexPath) as? OrderChargeTableViewCell

        } else {

            cell = tableView.dequeueReusableCell(withIdentifier: OrderChargeTableViewCell.regularCellIdentifier,
                                                 for: indexPath) as? OrderChargeTableViewCell

        }

        cell?.keyLabel.text = myData[indexPath.row].title

        let val = myData[indexPath.row].value
        cell?.valueLabel.text = String(format: "%0.02f USD", val)

        return cell!

    }

}

Это результат:

enter image description here

0 голосов
/ 04 декабря 2018

Это решение грубой силы, которым я вообще не горжусь, но оно здесь для справки (не пометит его как правильный ответ):

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    let orderChargesSection = self.getOrderChargesSection()
    switch indexPath.section {
        case orderChargesSection:
            return self.getCellHeightForOrderCharges(row: indexPath.row)
        default:
            return UITableViewAutomaticDimension
    }
}

private func getCellHeightForOrderCharges(row: Int) -> CGFloat {
   let numRows = self.tableView(self.tableView, numberOfRowsInSection: self.getOrderChargesSection())
    if (row == numRows - 1) {
        return UITableViewAutomaticDimension
    } else {
        return 25.5
    }
}
...