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

セクション単位で折りたためる、アコーディオン効果付きのUITableViewの作り方

More than 3 years have passed since last update.

セクション単位で折りたたむことのできるUITableViewを、ネットの情報をいろいろ調べながら作成していたのですが、どれもいろいろ気になるところがあって自分なりの実装をしてみました。気になるところもあり完成版ではないのですが、iOSの得意な人に指摘してもらえれば嬉しいです。

完成イメージ

ExpandTableView.gif

ヘッダーのタップイベント取得

UITableViewは、ヘッダー部分をタップしたときのイベントを取得する機能がありません。このイベントを取得するために、ネットでは次の方法を見つけることができました。

しかしどれも無理矢理感がありしっくりこなかったので、ヘッダー位置のセルをカスタムで作成してGestureを登録するようにしてみた。

ViewController.swift
    override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        var cell = tableView.dequeueReusableHeaderFooterViewWithIdentifier("Header") as? CustomHeaderFooterView
        if cell == nil {
            cell = CustomHeaderFooterView(reuseIdentifier: "Header")
            cell?.addGestureRecognizer(UITapGestureRecognizer(target: self, action: "tapHeader:"))
        }
        cell!.textLabel!.text = self.sections[section].title
        cell!.section = section
        cell!.setExpanded(self.sections[section].extended)
        return cell
    }

    func tapHeader(gestureRecognizer: UITapGestureRecognizer) {
        guard let cell = gestureRecognizer.view as? CustomHeaderFooterView else {
            return
        }
        let extended = self.sections[cell.section].extended
        self.sections[cell.section].extended = !extended
        tableView.reloadData()  // 追記で、reloadSectionsに変更しています
    }
CustomHeaderFooterView.swift
import UIKit

class CustomHeaderFooterView: UITableViewHeaderFooterView {
    private var arrow = UIImageView()
    var section: Int = 0

    override init(reuseIdentifier: String?) {
        super.init(reuseIdentifier: reuseIdentifier)
        self.arrow.translatesAutoresizingMaskIntoConstraints = false
        self.contentView.addSubview(self.arrow)
        self.contentView.addConstraints([
            NSLayoutConstraint(item: arrow, attribute: .Trailing, relatedBy: .Equal, toItem: self.contentView, attribute: .Trailing, multiplier: 1.0, constant: -8),
            NSLayoutConstraint(item: arrow, attribute: .CenterY, relatedBy: .Equal, toItem: self.contentView, attribute: .CenterY, multiplier: 1.0, constant: 0)])
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    func setExpanded(expanded: Bool) {
        arrow.image = UIImage(named: expanded ? "ArrowUp" : "ArrowDown")
    }
}

セルの表示非表示

ヘッダーのイベント発生時にセルの表示非表示を制御するために、データソースからデータを削除する方法で実装しているものがありました。しかし、表示のためにデータソースそのものを編集するのはどうかなあと思ったので、tableView:numberOfRowsInSection:メソッドで、折りたたんでいるときには0件を返すようにしてみました

ViewController.swift
    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
        return self.sections[section].extended ? sections[section].details.count : 0
    }

気になっているところ

  • セクションをタップしたときに、スクロール位置がずれることがある
  • アニメーション効果が入っていない
  • セクションをタップしたときに`tableView.reloadData()'で全レコードを更新している

追記しました

追記(アニメーション効果とtableView.reloadDataについて)

tableView.reloadSectionsを使うと、いい感じにアニメーションがついて、なおかつ対象となるセクションのみreloadするようになりました。

ViewController.swift
    func tapHeader(gestureRecognizer: UITapGestureRecognizer) {
        guard let cell = gestureRecognizer.view as? CustomHeaderFooterView else {
            return
        }
        let extended = self.sections[cell.section].extended
        self.sections[cell.section].extended = !extended
        tableView.reloadSections(NSIndexSet(index: cell.section), withRowAnimation: .None)
    }

ソースはこちらです。
https://github.com/nakaken0629/ExpandTableViewSample

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
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  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
ユーザーは見つかりませんでした