UITableView セルのサイズを自動的に変更する


スタータープロジェクト

スタータープロジェクトでは、テーブルビューのセルに UITextView が一つだけあり、それには次のようなビューの制約(レイアウト)が含まれています:

このプログラムビュー Storyboard では、テキストが表示されるはずです。

しかしプログラムを実行しても画面には何も表示されません。テーブルビューのセルの高さが0になっているようです。

この記事ではこの問題の修正の仕方について学んでいきます。

問題を修正する

スクロールを無効化する

デフォルトでは UITextView はスクロールが有効になっています。固定した高さにするためにそれを無効化する必要があります。

もともと、次のようなテーブルビューのクラスコードになっています。

class demoCell: UITableViewCell {
    @IBOutlet weak var textField: UITextView!
}

このコードを次のように更新します。

class demoCell: UITableViewCell {

    @IBOutlet weak var textField: UITextView!

    override func awakeFromNib() {
        super.awakeFromNib()
        textField.isScrollEnabled = false
    }

}

再びシミュレーターでプログラムを実行すれば、UITextView のコンテンツが正常に表示されているのがわかります。

テキストの内容が変更された時にビューの高さを更新する。

UITextView ]内のテキストを編集しようとしても、テーブルビューのセルの高さは変わりません。しかし、高さは動的に変更する必要があります。

自動で高さを設定する

テーブルビューのセルの高さを自動的に設定するようにシステムに指示することができます。

tableView.rowHeight = UITableView.automaticDimension

テキストの編集と連動させる

UITextViewDelegate を設定して、テキストが変更されたときにイベントが連動するようにします

class demoCell: UITableViewCell, UITextViewDelegate {

    @IBOutlet weak var textField: UITextView!

    override func awakeFromNib() {
        super.awakeFromNib()
        textField.isScrollEnabled = false
        textField.delegate = self
    }

    func textViewDidChange(_ textView: UITextView) {
        //新しいテキスト

    }

}

テキスト編集をテーブルビューコントローラに報告する

この変更を UITableViewController に報告すると、UITableViewController がテーブルビューをリフレッシュしてセルの高さが更新されます。

プロトコルを作成する

protocol demoCellDelegate : AnyObject {
    func textDidChange()
}

テーブルビューのセルで、demoCellDelegate.textDidChange() の関数を呼び出します

class demoCell: UITableViewCell, UITextViewDelegate {

    @IBOutlet weak var textField: UITextView!

    weak var delegate: demoCellDelegate?

    override func awakeFromNib() {
        super.awakeFromNib()
        textField.isScrollEnabled = false
        textField.delegate = self
    }

    func textViewDidChange(_ textView: UITextView) {
        //新しいテキスト
        delegate?.textDidChange()
    }

}

そして、テーブルビューのクラスで、デリゲートを設定します:

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "demo") as! demoCell
    cell.textField.text = "テスト テスト テスト テスト テスト テスト テスト テスト テスト テスト テスト"
    cell.delegate = self
    return cell
}
extension ViewController: demoCellDelegate {

    func textDidChange() {
        //TODO
    }

}

テーブルをリロードせずにテーブルビューを更新する

ここで、テーブルの高さを更新するために、reloadData() を使用しないでください。代わりに tableView.beginUpdates()tableView.endUpdates() を使用してください。

extension ViewController: demoCellDelegate {

    func textDidChange() {
        tableView.beginUpdates()
        tableView.endUpdates()
    }

}

そして、このプログラムをシミュレータで再度実行すると、次のようになります。


Twitter @MszPro

私の公開されているQiita記事のリストをカテゴリー別にご覧いただけます。