Swift: カスタムセルでTableViewを細かくセクション切りする

2020-03-06

こんつぁ、しょーです。

さて、TableViewの話をしよう。

超絶シンプルなアプリ、画面構成でない限り、ただリストを表示だけというのは少ないと思います。
大体はAPIレスポンスに応じて動的に表示したり、一画面にいくつかセクションが切られてあったり、セクションごとに見出し(ヘッダー)を用意せねばいかんこともあると思います。

業務で使っている構成が使いやすいので備忘録。

実装したい条件

APIレスポンスに応じて、データを動的にリスト表示させたい時は多いと思います。
一画面に複数セクションを切って、別々な情報を羅列したい時もあると思います。

image.png

上記のように、3つの別のセクションがあり、セクションごとに別のカスタムセルを使用しなければいけないケースなど、ちょっと考えるのが面倒です。

そういう場合はセクションヘッダーもまとめてカスタムセルで作成してしまいましょう。

セクションもカスタムビューを割り当てて作成できますが、tableView.grouped設定したり、設定したらしたで細かい設定も必要なので1つの案として。

考え方

切り分けは以下のように考えます。

セクション切りは、

  • (sectionA's header, sectionA's cells)
    というグルーピングではなく、
  • (sectionA's header), (sectionA's cells), (sectionB's header)...
    という切り方をしてnumberOfSectionsに設定します。

この構成の何が嬉しいかというと、

  • enum Section型を作成し、それをベースにした配列を用意することで、cellForRowAtswitch分岐できる
  • セクション数とsections配列の数が比例しているので、switch sections[indexPath.section]セルの種類ごと=セクションの種類ごとに分岐可能
  • case sectionA([String])と配列を与えているので、numberOfRowsInSectionでセクション毎のセル数をカウントして返せる

上記の構成をすることで、実際にcellForRowAtでセル作成していくときに
indexPath.section indexPath.rowの数とsectionsの構成している値の数がマッチして操作しやすいです。

コード

実際にcellForRowAtも加えると以下のようになります。

な感じになります。すごく使い勝手がいいです。

enum caseに上記ではStringを与えていますが、別に構造体でもいいですし、ベースとなるenum Sectionにケースを用意し、
処理を組んでからsectionsに値を返すようにすれば、APIレスポンスから動的に構成を整えることも可能です。

この辺とかでmapしたりreduceしたり。
Swift: map()でゴチャついた処理をreduce(into:)でスッキリ

何より全てカスタムセルで成しているのと、cellForRowAtがすごくリーダブルなのが魅力です。

まとめ

こういう引き出しというか、実装アイデアテンプレートみたいなのをたくさんおきたいねー。

はい、お疲れ様でした。