Posted at

UITableViewにて、セルの高さを画面へ描画後に変更する


概要



  • UITableView.rowHeight = UITableViewAutomaticDimension が諸事情によりされていない or できないテーブルビューのお話

  • 描画後なので、UITableViewDelegate
    のメソッドtableView(_:heightForRowAt:) はすでに走った後に該当セルについて高さを変える方法

  • 既存のソースコードで上記を実現するため、UITableView.reloadData()が呼ばれていたのを止めるために試行した内容と結果のメモ


セルの高さを変更したときに画面へ反映する処理


差し替え前


ViewController.swift

tableView.reloadData()



差し替え後


ViewController.swift

if #available(iOS 11.0, *) {

tableView.performBatchUpdates(nil, completion: nil)
} else {
tableView.beginUpdates()
tableView.endUpdates()
}

beginUpdates()endUpdates()が将来的に非推奨になるらしいコメントが記載されていたので、performBatchUpdates(_:completion:)を引数空で呼ぶ形。

iOS11以上のみのサポートの場合は、elseスコープの処理は不要。


セルの高さを変更する処理の中身


  • セル内で画像URLから実際に画像取得完了後、画像の縦横比を計算

  • UIImageViewの縦横比率について、デフォルト値(4:3)でなければNSLayoutConstraintの設定を差し替え


    • この処理を行う先がUITableViewCellでなければ変更完了後にupdateConstraints()などを呼んであげると素直に反映されるはずという内容




結論に至るまでに試したこと


該当セルにてreloadRows(at:with:)を呼ぶ

高さ以外の要素を変更したい場合はこの処理だけでいけるはずだが、変更後の高さは反映されず。


beginUpdates()endUpdates()の間にレイアウト更新処理を挟む

performBatchUpdates(_:completion:)では、1個目の引数に完了後に表示を更新したい処理をクロージャで渡す処理と同等。

updateConstraints()辺りが必要だろうと入れてたのだけど、上記の差し替え後の挙動と何ら変わらず。

少なくとも今回のパターンでは必要なく、本来の用途?(該当セルのリロード・削除など)ではこの対応が必要。


参考

StackOverflowの「How to dynamically resize UITableViewCell height」の回答の1つ