Динамически изменять высоту UITableViewCell - Swift 4 - PullRequest
0 голосов
/ 11 сентября 2018

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

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    let cell = tableView.cellForRow(at: indexPath) as! AvailableRideCell
    return cell.getHeight()
}

Это функция getHeight в моем AvailableRideCell

func getHeight() -> CGFloat {
    return self.destinationLabel.optimalHeight + 8 + self.originLabel.optimalHeight + 8 + self.priceLabel.optimalHeight
}

И это optimalHeight функция

extension UILabel {
    var optimalHeight : CGFloat {
        get {
            let label = UILabel(frame: CGRect(x: 0, y: 0, width: self.bounds.width, height: CGFloat.greatestFiniteMagnitude))
            label.numberOfLines = 0
            label.lineBreakMode = NSLineBreakMode.byWordWrapping
            label.font = self.font
            label.text = self.text
            label.sizeToFit()
            return label.frame.height
        }
    }
}

Ответы [ 3 ]

0 голосов
/ 11 сентября 2018

Ваш код вызывает сбой из-за этой строки

let cell = tableView.cellForRow(at: indexPath) as! AvailableRideCell

С Документация Apple мы знаем, что этот метод используется для оптимизации.Вся идея состоит в том, чтобы получить высоту клеток, не тратя время на создание самих клеток.Таким образом, этот метод вызывается перед инициализацией любой ячейки, а tableView.cellForRow(at: indexPath) возвращает nil.Потому что ячеек еще нет.Но вы делаете принудительное развертывание с помощью as! AvailableRideCell, и ваш код падает.

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

Например, в своих проектах я использовал это решение

Строковая реализация

extension String {
    func height(for width: CGFloat, font: UIFont) -> CGFloat {
        let maxSize = CGSize(width: width, height: CGFloat.greatestFiniteMagnitude)
        let actualSize = self.boundingRect(with: maxSize,
                                           options: [.usesLineFragmentOrigin],
                                           attributes: [NSAttributedStringKey.font: font],
                                           context: nil)
        return actualSize.height
    }
}

Реализация UILabel

extension String {
    func height(for width: CGFloat, font: UIFont) -> CGFloat {
        let labelFrame = CGRect(x: 0, y: 0, width: width, height: CGFloat.greatestFiniteMagnitude)
        let label = UILabel(frame: labelFrame)
        label.numberOfLines = 0
        label.lineBreakMode = .byWordWrapping
        label.font = font
        label.text = self
        label.sizeToFit()
        return label.frame.height
    }
}

При этом все, что вам нужно, это вычислить вашу метку и сохранить ее шрифт.

var titles = ["dog", "cat", "cow"]

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    // number of rows is equal to the count of elements in array
    return titles.count
}

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    let cellTitle = titles[indexPath.row]
    return cellTitle.height(forWidth: labelWidth, font: labelFont)
}

Динамическое изменение высоты строк

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

tableView.reloadRows(at: [indexPath], with: .automatic)

Надеюсь, он вам поможет.

0 голосов
/ 11 сентября 2018

Вы не упоминаете, используете ли вы Auto Layout, но если вы используете, вы можете позволить Auto Layout управлять высотой каждой строки. Вам не нужно реализовывать heightForRow, вместо этого установите:

tableView.rowHeight = UITableViewAutomaticDimension

И настройте вашу UILabel с ограничениями, которые прикрепляют ее к представлению содержимого ячейки:

    let margins = contentView.layoutMarginsGuide
    NSLayoutConstraint.activate([
        cellLabel.leadingAnchor.constraint(equalTo: margins.leadingAnchor),
        cellLabel.trailingAnchor.constraint(equalTo: margins.trailingAnchor),
        cellLabel.topAnchor.constraint(equalTo: margins.topAnchor),
        cellLabel.bottomAnchor.constraint(equalTo: margins.bottomAnchor)
    ])

Каждая строка будет расширяться или сужаться в соответствии с размером внутреннего содержимого метки. Высота автоматически регулируется, если изменяется альбомная / книжная ориентация устройства без перезагрузки ячейки. Если вы хотите, чтобы высота строки изменялась автоматически при изменении UIContentSizeCategory устройства, установите следующее:

cellLabel.adjustsFontForContentSizeCategory = true
0 голосов
/ 11 сентября 2018

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

Лучше всего иметь одну поддельную ячейку / заполнитель (я называю ячейкой калькулятора) и использовать ее для расчета размера ячейки.

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

...