Help us understand the problem. What is going on with this article?

iOS10 の UITableViewの高さが変わった時のアニメーションについて

More than 3 years have passed since last update.

はじめに

こんにちは
タップするなど、高さがアニメーションして変わるTableViewが
iOS 9以前 と iOS 10.0 で動きが少し異なってしまい、調べていたら見つけたので
まとめてみたいと思います。
至らぬ点など多々あると思いますが、コメントなど頂けたら幸いです。

デモ

実行時(iOS 9以前)

7-3-1.gif

実行時(iOS 10)

8.gif

(見づらくてごめんなさい...)
iOS 10だと高さを変えた時にセル同士のラベルが重なっているように見えてしまいます。

TableViewをreloadするタイミングでアニメーションを設定すると良い?

アニメーションして高さが変わるTableViewのセルをリロードする時は

tableView.reloadData()

ではなく

tableView.beginUpdates()
//データを変更する処理など
tableView.endUpdates()

とメソッドで挟むように記述します。そのTableViewに乗っているCellを

CustomTableViewCell.swift
override func layoutSubviews() {
    super.layoutSubviews()
    if #available(iOS 10, *) {
        UIView.animate(withDuration: 0.3) { self.contentView.layoutIfNeeded() }
    }
}

のようにアニメーションを設定するとiOS 9以前の動きにできるみたいです。

もう1つの方法とその違い

また、以下のように設定する方法もあるみたいです。

UIView.animate(withDuration: 0.3) {
    self.tableView.beginUpdates()
    //セルのデータを変更する処理など
    self.tableView.endUpdates()
    cell.layoutIfNeeded()
}

実行時(iOS 10)(わかりやすく色を付けてみました)

color.gif

この記述だとセルが小さく戻る時に、
他のセルの上を股がるようにアニメーションしてしまいます。
(緑・茶色のセルが画面に表示される際に水色の下から順に表示されるようなアニメーション)

サンプルコード

一応gifのコードを貼っておきたいと思います。

CustomTableViewCell.swift
import UIKit

class CustomTableViewCell: UITableViewCell {
    @IBOutlet weak var label: UILabel!

    var isOpen = false

    override func awakeFromNib() {
        super.awakeFromNib()
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        if #available(iOS 10, *) {
            UIView.animate(withDuration: 0.3) { self.contentView.layoutIfNeeded() }
        }
    }
}
MainViewController.swift
import UIKit

class MainViewController: UIViewController {
    @IBOutlet weak var tableView: UITableView!

    var cellTexts = ["AAA","BBB","CCC","DDD","EEE"]
    var openHeights: [CGFloat] = [308,132,132,132,132]
    var colors: [UIColor] = [UIColor.red,UIColor.blue,UIColor.cyan,UIColor.green,UIColor.brown]
    var isOpens = [false,false,false,false,false]

    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.delegate = self
        tableView.dataSource = self
        let nib = UINib(nibName: "CustomTableViewCell", bundle: nil)
        tableView.register(nib, forCellReuseIdentifier: "CustomTableViewCell")
    }
}

extension MainViewController: UITableViewDataSource {
    //テーブルの行ごとのセルを返却するメソッド
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "CustomTableViewCell", for:indexPath) as! CustomTableViewCell
        cell.selectionStyle = .none
        cell.label.text = cellTexts[indexPath.row]
        cell.isOpen = isOpens[indexPath.row]
        cell.backgroundColor = colors[indexPath.row]
        return cell
    }

    //テーブルの行数を返却するメソッド
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return cellTexts.count
    }
}

extension MainViewController: UITableViewDelegate {
    //セルを選択した時の処理
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let cell = tableView.cellForRow(at: indexPath) as! CustomTableViewCell
        UIView.animate(withDuration: 0.3) {
            self.tableView.beginUpdates()
            if cell.isOpen{
                cell.isOpen = false
                self.isOpens[indexPath.row] = false
            }else{
                cell.isOpen = true
                self.isOpens[indexPath.row] = true
            }
            self.tableView.endUpdates()
            cell.layoutIfNeeded()
        }

    }

    // テーブルセルの高さを返します
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return isOpens[indexPath.row] ? openHeights[indexPath.row] : 44
    }
}

参考にさせていただいたページ

このiOS 10のUITableViewのアニメーションについて

スタック・オーバーフロー

アニメーションするUITableViewについて

しめ鯖日記 さん

バージョンチェックについて

不満足こそが、極上を生む。さん

見て頂いてありがとうございます。

KikurageChan
見て頂いてありがとうございます。
https://kikuragechan.com
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away