Edited at

テーブルビューをセクションごとに開閉する

More than 1 year has passed since last update.

 やっはろー。セクションごとに開閉できるテーブルビュー、いわゆるアコーディオンメニューを実装したい、という話をします。

346 Production


開閉する

 セクションの開閉とは、つまるところ開閉の状態に応じたセル数の増減のことなので、そのようにします。

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

if self.openedSections.contains(section) {
return self.items[section].members.count
} else {
return 0
}
}


タップする

 タップを検知するために、セクションのヘッダにジェスチャを貼ります。タグにセクションの番号を入れると、タップしたセクションがすぐにわかって便利。

override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {

let view = UITableViewHeaderFooterView()
let gesture = UITapGestureRecognizer(target: self, action: #selector(self.tapSectionHeader(sender:)))
view.addGestureRecognizer(gesture)
view.tag = section

return view
}

@objc func tapSectionHeader(sender: UIGestureRecognizer) {

if let section = sender.view?.tag {
...
}
}


サンプルコード

 Playground で動くやつです。

import Foundation

import UIKit
import PlaygroundSupport

class ViewController: UITableViewController {
private let items = [
(type: "キュート", members: ["双葉", "緒方", "三村", "前川", "島村"]),
(type: "クール", members: ["神崎", "多田", "アナ", "新田", "渋谷"]),
(type: "パッション", members: ["諸星", "城ヶ崎", "赤城", "本田"]),
(type: "ミシロ", members: ["美城"]),
]

private var openedSections = Set<Int>()

@objc func tapSectionHeader(sender: UIGestureRecognizer) {
if let section = sender.view?.tag {
if self.openedSections.contains(section) {
self.openedSections.remove(section)
} else {
self.openedSections.insert(section)
}

self.tableView.reloadSections(IndexSet(integer: section), with: .fade)
}
}

// MARK: Table view data source

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
cell.textLabel?.text = self.items[indexPath.section].members[indexPath.row]

return cell
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if self.openedSections.contains(section) {
return self.items[section].members.count
} else {
return 0
}
}

override func numberOfSections(in tableView: UITableView) -> Int {
return self.items.count
}

// MARK: Table view delegate

override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return self.items[section].type
}

override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let view = UITableViewHeaderFooterView()
let gesture = UITapGestureRecognizer(target: self, action: #selector(self.tapSectionHeader(sender:)))
view.addGestureRecognizer(gesture)
view.tag = section

return view
}
}

let viewController = ViewController()
PlaygroundPage.current.liveView = viewController.view

楽しい!₍₍ (ง╹◡╹)ว ⁾⁾