[Swift]UITableViewCellを使ってTableViewに色々表示する


これは何?

僕がSwiftで分報アプリを作るにあたってタイムラインの実装をした時にTableViewにいろんな情報を表示させる時にちょっと苦戦したのでその戦いの記録です。

完成イメージ

完成のイメージはこれです↓↓↓

UITableViewCellクラスを利用してセルに色々表示する

セルに色々表示するに当たって、以下のことを順番にやっていきます。

  • 表示したいものを取得する
  • UITableViewCellクラスを作成する
  • TableViewにUITableViewCellクラスを紐づける
  • プロパティに表示したい内容をぶち込む

表示したいものを取得する

今回私は、分報アプリということで数十字程度の文字列日付をDomainの実装の段階で用意しました。
Domainでの実装についてはこちらをご覧ください↓↓↓
Swift+FirestoreでSNSライクなアプリを作る(Domain篇)

これらの情報はReportという構造体に入れています。

Report.swift
struct Report {
    var content: String
    var createdAt: Timestamp
}

通常、Firestoreから日付をそのまま取得するとTimestamp型で返ってきます。
今回カスタムセルには基本的に文字列しか入れられないので、まずはTimestampをString型に変換します。
やり方としては、Formatterを用意し、一度Date型として定義をし直してStringにキャストしています。

TimelineViewController.swift
extension TimelineViewController: UITableViewDataSource
{
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let formatter = DateFormatter()
        formatter.dateFormat = DateFormatter.dateFormat(fromTemplate: "ydMMM", options: 0, locale: Locale(identifier: "ja_JP"))

        let date = self.postedReports[indexPath.row].createdAt.dateValue()
        let dateText = formatter.string(from: date as Date)

UITableViewCellクラスを作成する

セル1つ1つの内容を管理するクラスを作成します。
このクラスを利用することで、表示する内容やセルのスタイルを設定することが出来ます。
詳しくはApple公式ドキュメントをご覧ください。

ReportCell.swift
class ReportCell: UITableViewCell
{
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: .subtitle, reuseIdentifier: "ReportCell")
    }

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

基本的にはドキュメントの記載通り、init()メソッドをオーバーライドするだけで良いのですが、
一つ注目してほしいのがセルのStyleについてです。

super.init(style: style, reuseIdentifier: reuseIdentifier)

Appleはいくつかのセルのスタイルを提供しており、init()メソッドの第1引数に指定をしてあげることでそのスタイルを変更することが出来ます。
スタイルの種類はこちらのドキュメントを参照すると4種類あり、それぞれ以下のように指定してあげることが出来ます。

super.init(style: .default, reuseIdentifier: reuseIdentifier)
super.init(style: .value1, reuseIdentifier: reuseIdentifier)
super.init(style: .value2, reuseIdentifier: reuseIdentifier)
super.init(style: .subtitle, reuseIdentifier: reuseIdentifier)

TableViewにUITableViewCellクラスを紐づける

作成したUITableViewCellクラスをtableViewに紐づけましょう。
紐づけは、UITableViewクラスのregister()メソッドを使います。

class TimelineViewController: UIViewController
{
    override func viewDidLoad() {    
        timelineView.register(ReportCell.self, forCellReuseIdentifier: "ReportCell")
    }

register()メソッドの第1引数には作成したUITableViewCellクラスを渡してあげます。
第2引数には、再利用のためにString型でカスタムセルクラスに対する名前を与えてあげます。
今回はややこしくなるのでクラス名と同じにしました。
もっと詳しいことは公式ドキュメントを参照してください。

これを忘れるといくらセルをカスタマイズしても変更されませんので注意してください。

プロパティに表示したい内容をぶち込む

表示するセルの設定も終わり、表示したいものも出揃ったところでようやくセルにぶち込んできます。

UITableViewCellクラスは、以下の3つのプロパティを用意しており、これに代入することでセルのStyleに合わせて表示をしてくれます。

var textLabel: UILabel? //メインの内容を表示できる
var detailTextLabel: UILabel? //サブコンテンツの表示に使える
var imageView: UIImageView? //サムネの表示とかはこれが使える

他にもcontentViewbackgroundViewなどがありますがとりあえず上の3つさえ使えばそれっぽくなります(?)

extension TimelineViewController: UITableViewDataSource
{

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let reportCell = tableView.dequeueReusableCell(withIdentifier: "ReportCell", for: indexPath)
        let date = self.postedReports[indexPath.row].createdAt.dateValue()

        reportCell.textLabel?.text = self.postedReports[indexPath.row].content
        reportCell.detailTextLabel?.text = formatter.string(from: date as Date)
        return reportCell
    }