Как программно развернуть и свернуть ячейки таблицы с динамической высотой? - PullRequest
0 голосов
/ 31 января 2019

Вот видео моей проблемы: https://imgur.com/a/qvGSLfD

Моя пользовательская ячейка имеет 2 метки: одну основную метку и метку субтитра, обе из которых ограничены contentView layoutMarginsGuide ячейки во всех направлениях.

Прежде всего, весь механизм разворачивания развертывания кажется немного неуклюжим, поскольку я активирую и деактивирую ограничения, а затем перезагружаю indexPaths.

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

В принципе, я мог бы сделать что-то вроде этого:

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    if indexPath.row == selectedRowIndex {
        return 200 //Expanded
    }
    return tableView.rowHeight //Not expanded
}

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

Вот мой код tableView в моем классе viewController:

 var tableView: UITableView = {
    let tv = UITableView(frame: .zero)
    tv.register(CustomCell.self, forCellReuseIdentifier: CustomCell.reuseIdentifier())
    tv.translatesAutoresizingMaskIntoConstraints = false
    tv.rowHeight = UITableView.automaticDimension
    tv.estimatedRowHeight = 60.0
    tv.estimatedSectionHeaderHeight = 0
    tv.estimatedSectionFooterHeight = 0
    tv.showsVerticalScrollIndicator = false
    tv.tableFooterView = UIView()
    tv.alwaysBounceVertical = true
    tv.decelerationRate = .fast
    tv.bounces = false
    tv.dataSource = self
    tv.delegate = self
    return tv
}()

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: CustomCell.reuseIdentifier(), for: indexPath) as! CustomCell
    cell.bounds = CGRect(x: 0, y: 0, width: tableView.bounds.width, height: 99999)
    cell.contentView.bounds = cell.bounds
    cell.layoutIfNeeded()
    cell.wordLabel.preferredMaxLayoutWidth = cell.wordLabel.frame.width
    cell.descriptionLabel.preferredMaxLayoutWidth = cell.descriptionLabel.frame.width

    //customize this later
    cell.backgroundColor = .white
    cell.set(content: datasource[indexPath.row])
    return cell
}

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    let cell = tableView.cellForRow(at: indexPath) as! CustomCell
    cell.toggle()
    tableView.reloadRows(at: [indexPath], with: .automatic)
}

Вот соответствующие пользовательские функции Cell:

var isExpanded: Bool!

private var singleLabelConstraints: [NSLayoutConstraint]!
private var doubleLabelConstraints: [NSLayoutConstraint]!

override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
    super.init(style: style, reuseIdentifier: reuseIdentifier)
    setupLabels()
}

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

func toggle() {
    isExpanded = !isExpanded
    if isExpanded == false {
        print("collapsed")
        self.descriptionLabel.isHidden = true
        NSLayoutConstraint.activate(singleLabelConstraints)
        NSLayoutConstraint.deactivate(doubleLabelConstraints)
    } else if isExpanded == true {
        print("expanded")
        self.descriptionLabel.isHidden = false
        NSLayoutConstraint.deactivate(singleLabelConstraints)
        NSLayoutConstraint.activate(doubleLabelConstraints)
    }
}

func setupLabels() {
    isExpanded = false
    descriptionLabel.isHidden = true
    self.contentView.addSubview(wordLabel)
    self.contentView.addSubview(descriptionLabel)

    singleLabelConstraints = [
        wordLabel.leadingAnchor.constraint(
            equalTo: self.contentView.layoutMarginsGuide.leadingAnchor,
            constant: labelInsets.left
        ),
        wordLabel.topAnchor.constraint(
            equalTo: self.contentView.layoutMarginsGuide.topAnchor,
            constant: labelInsets.top
        ),
        wordLabel.trailingAnchor.constraint(
            equalTo: self.contentView.layoutMarginsGuide.trailingAnchor,
            constant: labelInsets.right
        ),
        wordLabel.bottomAnchor.constraint(
            equalTo: self.contentView.layoutMarginsGuide.bottomAnchor,
            constant: labelInsets.bottom
        )
    ]

    doubleLabelConstraints = [
        wordLabel.leadingAnchor.constraint(
            equalTo: self.contentView.layoutMarginsGuide.leadingAnchor,
            constant: labelInsets.left
        ),
        wordLabel.topAnchor.constraint(
            equalTo: self.contentView.layoutMarginsGuide.topAnchor,
            constant: labelInsets.top
        ),
        wordLabel.trailingAnchor.constraint(
            equalTo: self.contentView.layoutMarginsGuide.trailingAnchor,
            constant: labelInsets.right
        ),

        descriptionLabel.leadingAnchor.constraint(
            equalTo: self.contentView.layoutMarginsGuide.leadingAnchor,
            constant: labelInsets.left
        ),
        descriptionLabel.topAnchor.constraint(
            equalTo: self.wordLabel.bottomAnchor,
            constant: labelInsets.top
        ),
        descriptionLabel.trailingAnchor.constraint(
            equalTo: self.contentView.layoutMarginsGuide.trailingAnchor,
            constant: labelInsets.right
        ),
        descriptionLabel.bottomAnchor.constraint(
            equalTo: self.contentView.layoutMarginsGuide.bottomAnchor,
            constant: labelInsets.bottom
        )
    ]
    NSLayoutConstraint.activate(singleLabelConstraints)
}

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

Ответы [ 3 ]

0 голосов
/ 31 января 2019

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

class ViewController: UIViewController {
    var tableView: UITableView = {
        let tv = UITableView(frame: .zero)
        tv.register(CustomCell.self, forCellReuseIdentifier: "CustomCell")
        tv.translatesAutoresizingMaskIntoConstraints = false
        tv.rowHeight = UITableView.automaticDimension
        tv.estimatedRowHeight = 100.0
        tv.estimatedSectionHeaderHeight = 0
        tv.estimatedSectionFooterHeight = 0
        tv.showsVerticalScrollIndicator = false
        tv.tableFooterView = UIView()
        tv.alwaysBounceVertical = true
        tv.decelerationRate = .fast
        tv.bounces = false
        return tv
    }()
    var selectedCell:IndexPath?

    override func viewDidLoad() {
        super.viewDidLoad()
        self.view.addSubview(tableView)
        tableView.dataSource = self
        tableView.delegate = self
        self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[tableView]|", options: [], metrics: nil, views: ["tableView":tableView]))
        self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[tableView]|", options: [], metrics: nil, views: ["tableView":tableView]))
    }


}
extension ViewController: UITableViewDataSource, UITableViewDelegate {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 10
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell") as? CustomCell ?? CustomCell()
        if let selectedCell = selectedCell, selectedCell == indexPath {
            cell.descriptionLabel.isHidden = false
        } else {
            cell.descriptionLabel.isHidden = true
        }
        return cell
    }
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        selectedCell = indexPath
        tableView.reloadData()
    }
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return UITableView.automaticDimension
    }
    func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
        return 100
    }

}

class CustomCell: UITableViewCell {

    let stackView = UIStackView()
    let wordLabel = UILabel()
    let descriptionLabel = UILabel()

    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        setupLabels()
    }

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

    func setupLabels() {

        selectionStyle = .none

        stackView.axis = .vertical
        stackView.distribution = .equalSpacing
        stackView.spacing = 5
        stackView.alignment = .fill
        stackView.translatesAutoresizingMaskIntoConstraints = false
        self.contentView.addSubview(stackView)

        wordLabel.translatesAutoresizingMaskIntoConstraints = false
        wordLabel.text = "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lor"
        wordLabel.numberOfLines = 0
        wordLabel.lineBreakMode = .byWordWrapping
        stackView.addArrangedSubview(wordLabel)

        descriptionLabel.translatesAutoresizingMaskIntoConstraints = false
        descriptionLabel.text = "It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum."
        descriptionLabel.numberOfLines = 0
        descriptionLabel.lineBreakMode = .byWordWrapping
        stackView.addArrangedSubview(descriptionLabel)

        wordLabel.heightAnchor.constraint(greaterThanOrEqualToConstant: 30).isActive = true
        descriptionLabel.heightAnchor.constraint(greaterThanOrEqualToConstant: 30).isActive = true

        stackView.leadingAnchor.constraint(equalTo: self.contentView.layoutMarginsGuide.leadingAnchor,constant: 10).isActive = true
        stackView.topAnchor.constraint(equalTo: self.contentView.layoutMarginsGuide.topAnchor,constant: 10).isActive = true
        stackView.trailingAnchor.constraint(equalTo: self.contentView.layoutMarginsGuide.trailingAnchor,constant: 10).isActive = true
        stackView.bottomAnchor.constraint(equalTo: self.contentView.layoutMarginsGuide.bottomAnchor,constant: 10).isActive = true

    }
}
0 голосов
/ 04 февраля 2019

Здравствуйте, вы можете преодолеть проблему, пройдя по этой ссылке ниже:

http://vasundharavision.com/blog/ios/expandable-tableview-without-third-party

Я надеюсь, что это работает для вас.

0 голосов
/ 31 января 2019

Попробуйте это:

tableView.beginUpdates()
tableView.reloadRows(at: [indexPath], with: .automatic)
tableView.endUpdates()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...