Программно создавая расширяющийся UItableViewCell

У меня есть ячейка просмотра таблицы, которую я хочу развернуть и свернуть при нажатии. Все примеры, которые я нашел, основаны на раскадровке, и я пытаюсь сделать это программно. Сначала я думал создать подпредставление и ограничить его представлением содержимого, но когда я настраиваю высоту ячейки с помощью heightForRowAt это также увеличивает размер представления контента (что имеет смысл). Любые мысли о том, как я должен идти по этому поводу?

Для наглядности вот что я хочу чтобы произошло

3 ответа

Решение

Использовать вертикальный UIStackView с видом снизу isHidden установите в значение true, а затем нажмите (или что-то еще является триггером расширения) просто измените isHidden = false, Я думаю, это будет проще всего, учитывая, как UIStackView имеет дело с isHidden, Другой подход состоит в том, чтобы установить ограничения автоматического размещения и изменить привязку высоты нижнего вида, установив NSLayoutConstraintпостоянная к 0.

В любом случае, какой бы метод выбора вы ни выбрали, вам нужно будет указать tableView обновить его отображение (из viewcontroller):

func refreshTableAfterCellExpansion() {
    self.tableView.beginUpdates()
    self.tableView.setNeedsDisplay()
    self.tableView.endUpdates()
}

Например, проверьте следующий ТАК вопрос и его ответ.

Пример использования игровых площадок (один с UIStackViewдругой использует тот же принцип):

import UIKit
import PlaygroundSupport

class ExpandableCellViewController: UITableViewController, ExpandableCellDelegate {

    override func loadView() {
        super.loadView()

        tableView.rowHeight = UITableViewAutomaticDimension
        tableView.estimatedRowHeight = 44
        tableView.register(ExpandableCell.self, forCellReuseIdentifier: "expandableCell")
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 5
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "expandableCell", for: indexPath) as! ExpandableCell
        cell.delegate = self
        return cell
    }

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        if let cell = tableView.cellForRow(at: indexPath) as? ExpandableCell {
            cell.isExpanded = true
        }
    }

    override func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
        if let cell = tableView.cellForRow(at: indexPath) as? ExpandableCell {
            cell.isExpanded = false
        }
    }

    func expandableCellLayoutChanged(_ expandableCell: ExpandableCell) {
        refreshTableAfterCellExpansion()
    }

    func refreshTableAfterCellExpansion() {
        self.tableView.beginUpdates()
        self.tableView.setNeedsDisplay()
        self.tableView.endUpdates()
    }
}

protocol ExpandableCellDelegate: class {
    func expandableCellLayoutChanged(_ expandableCell: ExpandableCell)
}

class ExpandableCell: UITableViewCell {
    weak var delegate: ExpandableCellDelegate?

    fileprivate let stack = UIStackView()
    fileprivate let topView = UIView()
    fileprivate let bottomView = UIView()

    var isExpanded: Bool = false {
        didSet {
            bottomView.isHidden = !isExpanded
            delegate?.expandableCellLayoutChanged(self)
        }
    }

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

        selectionStyle = .none

        contentView.addSubview(stack)
        stack.addArrangedSubview(topView)
        stack.addArrangedSubview(bottomView)

        stack.translatesAutoresizingMaskIntoConstraints = false
        topView.translatesAutoresizingMaskIntoConstraints = false
        bottomView.translatesAutoresizingMaskIntoConstraints = false

        NSLayoutConstraint.activate([
            stack.topAnchor.constraint(equalTo: contentView.topAnchor),
            stack.leftAnchor.constraint(equalTo: contentView.leftAnchor),
            stack.rightAnchor.constraint(equalTo: contentView.rightAnchor),
            stack.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),

            topView.heightAnchor.constraint(equalToConstant: 50),

            bottomView.heightAnchor.constraint(equalToConstant: 30),
            ])

        stack.axis = .vertical
        stack.distribution = .fill
        stack.alignment = .fill
        stack.spacing = 0

        topView.backgroundColor = .red
        bottomView.backgroundColor = .blue
        bottomView.isHidden = true
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

// Present the view controller in the Live View window
PlaygroundPage.current.liveView = ExpandableCellViewController()

Я бы просто определил 2 типа ячеек и выбрал тот, который подходит для tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath)

Вы можете использовать флаг, чтобы указать, развернут ли конкретный раздел или строка, и использовать эти методы в UITableView:

    reloadRows()
    reloadSections()

И измените метод heightForRow, чтобы он возвращал нужную высоту в соответствии с флагом Если вы хотите иметь возможность расширять более одной строки за раз, вы можете использовать ViewModel для каждого элемента в вашем источнике данных и обновлять флаг в нем при вызове методов didSelectItemAt или didDeselectItemAt, а затем перезагружать строку или раздел с нужной анимацией.

Другие вопросы по тегам