iOS
tableView
Swift
a++
swift4

【iOS】アコーディオン(折りたたみ)式テーブルビューを作る!!

More than 1 year has passed since last update.

こういうのがつくりたいとき

AccordionTableView.mov.gif

・セルが折りたたまれるテーブルビュー
・セクションありのセルと、なしのセルがある

どうつくるか

ライブラリを使用して実装しました。
→ LUExpandableTableView

つくる

<手順>
1. ライブラリインストール(cocoapod, carthage,..)
2. LUExpandableTableViewクラスのtableView作成
4. セクション用のセル作成(LUExpandableTableViewSectionHeaderクラスを使用)
5. xib登録
6. デリゲート設定
7. デリゲートメソッドの実装

通常のtableViewを使用するときと同じです!
使用するtableViewのクラスをLUExpandableTableView, セクション用のviewクラスをLUExpandableTableViewSectionHeaderにするだけ。
あとは好きなようにカスタムっ

セクションありのセル、セクションなしのセルを設定したい!

・セクションなし
→ セクションの高さを0に設定。expand状態にする

ViewController.swift
func expandableTableView(_ expandableTableView: LUExpandableTableView, heightForHeaderInSection section: Int) -> CGFloat {

        if section == 0 || section == 3 {
            // 高さを0に
            return 0
        } else {
            return 69
        }
    }
ViewController.swift
override func viewDidLoad() {
        super.viewDidLoad()

        expandableTableView.register(MyTableViewCell.self, forCellReuseIdentifier: cellReuseIdentifier)
        expandableTableView.register(UINib(nibName: "MyExpandableTableViewSectionHeader", bundle: Bundle.main), forHeaderFooterViewReuseIdentifier: sectionHeaderReuseIdentifier)

        expandableTableView.expandableTableViewDataSource = self
        expandableTableView.expandableTableViewDelegate = self

        // セクションいらないところは、開いた状態にしておく(引数はセクションの位置)
        expandableTableView.expandSections(at: [0])
        expandableTableView.expandSections(at: [3])
    }

開いたり、閉じたりした時に何かしたい!

isExpandedの値をみて処理をすればOK

MyExpandableTableViewSectionHeader.swift
//セクション用のviewクラス

final class MyExpandableTableViewSectionHeader: LUExpandableTableViewSectionHeader {
    // MARK: - Properties

    @IBOutlet weak var expandCollapseButton: UIButton!
    @IBOutlet weak var label: UILabel!

    override var isExpanded: Bool {
        didSet {
            // Change the title of the button when section header expand/collapse
            // 開いてたらボタンのテキストを「Collapse」 、 閉じてたら「Expand」
            expandCollapseButton?.setTitle(isExpanded ? "Collapse" : "Expand", for: .normal)
        }
    }

セクションのタップイベント時に何かさせたい!

・開いたり、閉じたりをタップ時にさせたい
→ delegate?.expandableSectionHeader(self, shouldExpandOrCollapseAtSection: section) を記述すればOK。

・タップ時の通知をViewControllerに送る
→ タップを検出できる要素をつくる
→ タップ検出タイミングで、delegate?.expandableSectionHeader(self, wasSelectedAtSection: section) を呼べば、デリゲートメソッドの didSelectSectionHeader が呼ばれるので、そこでセクションタップ後にしたい処理を書く。

MyExpandableTableViewSectionHeader.swift
final class MyExpandableTableViewSectionHeader: LUExpandableTableViewSectionHeader {
    // MARK: - Properties

    @IBOutlet weak var expandCollapseButton: UIButton!
    @IBOutlet weak var label: UILabel!

    override var isExpanded: Bool {
        didSet {
            // Change the title of the button when section header expand/collapse
            expandCollapseButton?.setTitle(isExpanded ? "Collapse" : "Expand", for: .normal)
        }
    }

    // MARK: - Base Class Overrides

    override func awakeFromNib() {
        super.awakeFromNib()
        // ラベルをタップ検出可能にする
        label?.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(didTapOnLabel)))
        label?.isUserInteractionEnabled = true
    }

    // MARK: - IBActions

    @IBAction func expandCollapse(_ sender: UIButton) {
        // セクションの中にあるボタンタップで開いたり、閉じた
        // セクションの色を変えたりとかも!
        delegate?.expandableSectionHeader(self, shouldExpandOrCollapseAtSection: section)
    }

    // MARK: - Private Functions

    @objc private func didTapOnLabel(_ sender: UIGestureRecognizer) {
        // ラベルタップ時に選択された情報を通知する
        delegate?.expandableSectionHeader(self, wasSelectedAtSection: section)
    }
}

ViewContoroller.swift
    func expandableTableView(_ expandableTableView: LUExpandableTableView, didSelectSectionHeader sectionHeader: LUExpandableTableViewSectionHeader, atSection section: Int) {
        // ラベルがタップされた時にここがはしる
        //  セクション内のセルの色かえたりとかテキストを変えたり
        print("Did select section header at section \(section)")
    }

おわり

LUExpandableTableView のサンプルプロジェクトとか、readmeを読めば簡単に実装できると思います!
本投稿が理解の一助となれば幸いです!