Как получить высоту UITableView, когда ячейки имеют динамический размер?

У меня есть UITableView с ячейками с динамическим размером. Это означает, что я установил:

tableView.estimatedRowHeight = 50.0
tableView.rowHeight = UITableViewAutomaticDimension

Теперь я хочу получить высоту всего представления таблицы. Я попытался получить его через tableView.contentSize.height, но это возвращает только примерную высоту строки, а не фактическую динамическую высоту представления таблицы.

Как получить динамическую высоту всего представления таблицы?

Ответ 1

Я, наконец, взломал решение:

tableView.contentSize.height не будет работать для динамических ячеек, потому что они возвратят только число ячеек * estimatedRowHeight.

Следовательно, чтобы получить высоту динамической таблицы, вы ищете все видимые ячейки и суммируйте их высоты. Обратите внимание, что это работает только для табличных представлений, которые короче экрана.

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

  • Задайте высоту ограничения табличного представления:

    // Class variable heightOfTableViewConstraint set to 1000
    heightOfTableViewConstraint = NSLayoutConstraint(item: self.tableView, attribute: .height, relatedBy: .equal, toItem: containerView, attribute: .height, multiplier: 0.0, constant: 1000)
    containerView.addConstraint(heightOfTableViewConstraint)
    
  • Вызовите tableView.layoutIfNeeded(), и когда закончите, найдите видимые ячейки, суммируйте их высоту и отредактируйте heightOfTableViewConstraint:

    UIView.animate(withDuration: 0, animations: {
        self.tableView.layoutIfNeeded()
        }) { (complete) in
            var heightOfTableView: CGFloat = 0.0
            // Get visible cells and sum up their heights
            let cells = self.tableView.visibleCells
            for cell in cells {
                heightOfTableView += cell.frame.height
            }
            // Edit heightOfTableViewConstraint constant to update height of table view
            self.heightOfTableViewConstraint.constant = heightOfTableView
    }
    

Ответ 2

на него уже был дан ответ, но я хочу поделиться своим опытом.

У меня та же проблема. Я искал ответы во многих похожих вопросах и пытался их ответы и не работал.

Наконец, я нашел leonardloo answer. Большое спасибо, но он еще не решил мою проблему. Я просто хочу закончить его ответ. Я поставил этот код из своего ответа:

UIView.animate(withDuration: 0, animations: {
self.tableView.layoutIfNeeded()
}) { (complete) in
    var heightOfTableView: CGFloat = 0.0
    // Get visible cells and sum up their heights
    let cells = self.tableView.visibleCells
    for cell in cells {
        heightOfTableView += cell.frame.height
    }
    // Edit heightOfTableViewConstraint constant to update height of table view
    self.heightOfTableViewConstraint.constant = heightOfTableView
}

в этом блоке кода:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    ...
    if indexPath.row == data.count-1{ 
        // Insert the code here
    }
    return cell
}

Это означает, что после того, как все строки в таблице были загружены, мы обновляем высоту строки, используя этот фрагмент кода. Он работает!!!

Ответ 3

Вы можете добавить это в расширениях.

Свифт 4:

extension UITableView {

    // sums the height of visible cells
    func heightOfVisibleCells() -> CGFloat {
        return self.visibleCells.map({ $0.frame.height }).reduce(0, +)
    }

}

Ответ 4

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

У меня был большой tableView с большими строками, и у меня была та же проблема. Когда я применил ответ @leonardloo, я увидел, что он рисует только количество видимых ячеек, которые он обнаружил в начале, и он рисует 1 строку, тогда как он должен нарисовать 5 (мой источник данных).

Чтобы исправить это, я нашел такое простое решение:

UIView.animate(withDuration: 0, animations: {
self.tableView.layoutIfNeeded()
}) { (complete) in
    var heightOfTableView: CGFloat = 0.0
    // Get visible cells and sum up their heights
    let cells = self.tableView.visibleCells
    for cell in cells {
        heightOfTableView += cell.frame.height
    }
    // Edit heightOfTableViewConstraint constant to update height of table view
    // Set tableView constraint to height + 1 so that 
    // it can still draw the next visible cell it supposed to.
    self.heightOfTableViewConstraint.constant = heightOfTableView + 1
}

Смысл здесь в том, чтобы позволить ему нарисовать следующую ячейку, чтобы она также учитывалась в visibleCells, установив константу ограничения на высоту +1. Я проверил, и теперь кажется, что это работает как шарм.

Ответ 5

Вы должны рассчитать высоту tableView в следующем методе делегата,

func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {

    //Get the height required for the TableView to show all cells
    if indexPath.row() == (tableView.indexPathsForVisibleRows.last! as! NSIndexPath).row {
        //End of loading all Visible cells
        float heightRequiredForTable = tableView.contentSize.height

        //If cell are more than 10 or so that it could not fit on the tableView visible area then you have to go for other way to check for last cell loaded 
    }
}

Ответ 6

Мы можем использовать расширение UITableView для получения высоты,

   extension UITableView {    

       ///Get visible cell height
       var visibleCellsHeight: CGFloat {
            return visibleCells.reduce(0) { $0 + $1.frame.height }
       }
   }

Ответ 7

Просто сохраните массив типа CGFLoat и добавьте UITableViewAutomaticDimension в cellForRowAt indexPath делегат tableview

var cellHeight = [CGFloat]()
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
cellHeight.append(UITableViewAutomaticDimension)
}

Ответ 8

Я добавлю свой ответ здесь, так как я немного боролся с этим.

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

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
  ... // do your normal cell processing

  // determine height and change it
  if indexPath.section == (self.sectionTitles.count - 1) && indexPath.row == (sectionData.count - 1) {

    UIView.animate(withDuration: 0, animations: {
      self.tableView.layoutIfNeeded()
    }) { complete in

      // Edit heightOfTableViewConstraint constant to update height of table view
      self.tableViewHeightConstraint.constant = self.tableView.contentSize.height
    }
  }
}

Ответ 9

вы можете попробовать этот код

func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    return UITableViewAutomaticDimension
}

func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    return UITableViewAutomaticDimension
}