【iOS】UITableViewのSectionHeaderとSectionFooterをdequeuで使いまわしできるようにする


iOS その3 Advent Calendar

3日目も書かせていただきます!

予約投稿最高!

ちなみに前日も書かせていただきました!

では本題です。

UITableViewのSectionHeaderとSectionFooterをdequeuで使いまわしできるようにする

多分難しいことを考えなければ以下のUITableViewDelegateを使って表示していると思います。

僕もそうでした。

ViewController.swift
class ViewController {
    @IBOutlet weak var tableView: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()
        self.tableView.delegate = self
    }
}

extension ViewController: UITableViewDelegate {

    func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
        // 適当な高さ
        return 80.0
    }

    func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        return CustomView()
    }

}

という感じかと思います。

ただそうすると以下の問題があります。

  • 他のイベント時にSection Header, Section Footerにアクセスすることができません。
  • なんか毎回生成処理するのめんどくさい

ちなみにですが...

UITableViewには以下のメソッドがあります。

  • func headerView(forSection section: Int) -> UITableViewHeaderFooterView?
  • func footerView(forSection section: Int) -> UITableViewHeaderFooterView?

というメソッドがありますが、上記の作り方だとアクセスしてもnilが返ってくるだけです。

このメソッドからアクセスできるようにしたいと思います。

UITableViewHeaderFooterView

最初はクラスで

UITableViewHeaderFooterViewを継承したクラスを作成してregister処理をします。

以下のようなクラスを作成したとします。

CustomTableViewHeaderFooterView.swift
class CustomTableViewHeaderFooterView: UITableViewHeaderFooterView {
    // 適当にレイアウト処理を施しているであろうLabel
    private let label: UILabel

    func setText(_ text: String?) {
        self.label.text = text
    }

}

これを大好きregister処理をします。

class ViewController {

    @IBOutlet weak var tableView: UITableView!

    // identifier
    private let headerfooterViewIdentifier = "CustomTableViewHeaderFooterView"

    override func viewDidLoad() {
        super.viewDidLoad()
        self.tableView.delegate = self

        self.tableView.register(CustomTableViewHeaderFooterView.self, forHeaderFooterViewReuseIdentifier: headerfooterViewIdentifier)
    }

}

で使うときは

extension ViewController: UITableViewDelegate {

    func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
        // 適当な高さ
        return 80.0
    }

    func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        let view = tableView.dequeueReusableHeaderFooterView(withIdentifier: headerfooterViewIdentifier)
        if let v = view as? CustomTableViewHeaderFooterView {
            v.setText("header!!!")
        }
        return view
    }

}

となります。

それではNibファイルを使って

やってみます。

以下のようなCustomTableViewHeaderFooterView.xibを作成してください。

接続していきます。

これを使用していきます。

class ViewController {

    @IBOutlet weak var tableView: UITableView!

    // identifier
    private let nibName = "CustomTableViewHeaderFooterView"

    override func viewDidLoad() {
        super.viewDidLoad()
        self.tableView.delegate = self

        let nib = UINib(nibName: nibName, bundle: nil)
        self.tableView.register(nib, forHeaderFooterViewReuseIdentifier: nibName)
    }

}

で使うときは

extension ViewController: UITableViewDelegate {

    func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
        // 適当な高さ
        return 80.0
    }

    func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        let view = tableView.dequeueReusableHeaderFooterView(withIdentifier: nibName)
        if let v = view as? CustomTableViewHeaderFooterView {
            v.setText("header!!!")
        }
        return view
    }

}

となります。

ちなみに他のイベントなどでsectionの色を変えたいなどの場合は

// 取得したいseciton
let section = 0
let view = self.tableView.headerView(forSection: section)
view.backgroundColor = UIColor.blue

というように扱うことができます。

終わりに

僕はこれでUITableViewのスクロールに合わせてSectionに下線を表示する、しないを実装しました。

参考