UITableViewCellの高さを自動調整するには、
UITableViewのrowHeightプロパティにUITableViewAutomaticDimensionを設定する方法がある。
だけど、この方法を使うにはTableView内の全てのセルにAutoLayoutが不足なく設定されていなければならない。
しかしレガシーなアプリだと、AutoLayoutが設定されていないものもあり、すべてのセルに対して設定し直すというのは面倒。
そんな時は、次のようにtableView:heightForRowAtメソッドで内容によって高さを調整したいセルの高さを計算して返す。
import UIKit
//各TableViewCellのIdentifier
private let topCellID = "topCellID"
private let middleCellID = "middleCellID"
private let bottomCellID = "bottomCellID"
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
@IBOutlet weak var mainTable: UITableView!
static let cellIDs: [String] = [topCellID, middleCellID, bottomCellID]
var cellTexts: [String: String] = [:]
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
mainTable.delegate = self
mainTable.dataSource = self
cellTexts[topCellID] = self.reapeatChar(targetChar: "上", repeatNum: 100) + "終"
cellTexts[middleCellID] = self.reapeatChar(targetChar: "中", repeatNum: 200) + "終"
cellTexts[bottomCellID] = self.reapeatChar(targetChar: "下", repeatNum: 300) + "終"
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// 行数
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return ViewController.cellIDs.count
}
// セルの高さ
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let cellId: String = ViewController.cellIDs[indexPath.row]
let cell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: cellId)!
if [topCellID, middleCellID, bottomCellID].contains(cellId) {
return self.getCellHeight(tableView: tableView, text: self.cellTexts[cellId]!)
}
return cell.bounds.height
}
// セルの中身
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellId: String = ViewController.cellIDs[indexPath.row]
let cell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: cellId)!
if cellId == topCellID {
let label = cell.viewWithTag(100) as! UILabel
label.text = cellTexts[cellId]
} else if cellId == middleCellID {
let label = cell.viewWithTag(100) as! UILabel
label.text = cellTexts[cellId]
} else if cellId == bottomCellID {
let label = cell.viewWithTag(100) as! UILabel
label.text = cellTexts[cellId]
}
return cell
}
// セクション数
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
// セルの高さを返す
private func getCellHeight(tableView: UITableView, text: String) -> CGFloat {
let maxMessageLabelWidth: CGFloat = UIScreen.main.bounds.size.width
let messageLabelHeight: CGFloat = self.getLabelSize(text: text, font: UIFont.systemFont(ofSize: 13.0), width: maxMessageLabelWidth, height: CGFloat.greatestFiniteMagnitude).height
return messageLabelHeight + 16 //ラベルの上下には間隔が空くので16ptほど余分に高さを設定
}
// 高さと幅を計算するメソッド
private func getLabelSize(text: String, font: UIFont, width: CGFloat, height: CGFloat) -> CGSize {
let maxSize: CGSize = CGSize(width: width, height: height)
let attr = [NSFontAttributeName: font]
let size: CGSize = text.boundingRect(with: maxSize,
options: [NSStringDrawingOptions.usesLineFragmentOrigin, NSStringDrawingOptions.truncatesLastVisibleLine],
attributes: attr,
context: nil).size
return size
}
private func reapeatChar(targetChar: String, repeatNum: Int) -> String {
var resStr: String = ""
for _ in 1 ... repeatNum {
resStr += targetChar
}
return resStr
}
}