📏

TableViewのSectionIndexTitlesの位置を調整する

2021/02/23に公開

はじめに

TableView でデータをリスト表示している際に、セクションをいい感じに表示してくれる SectionIndexTitles というものがあります。

連絡先アプリ ミュージック
Simulator Screen Shot - iPhone 8 - 2021-02-23 at 13 49 22 IMG_1540

この SectionIndexTitles は TableView のデリゲートメソッドである sectionIndexTitles(for:) を実装するだけで表示することができます。

func sectionIndexTitles(for tableView: UITableView) -> [String]? {
    // セクションごとに分けたデータのタイトル等
    return ["あ", "か", "さ" ...]
}

やりたかったこと

そんな SectionIndexTitles ですが、UISearchController などと一緒に使っていて、かつデータの量が多くなるとキーボードで隠れてしまうことがあります。

短いとき 長いとき
Simulator Screen Shot - iPhone 12 - 2021-02-23 at 15 04 36 Simulator Screen Shot - iPhone 12 - 2021-02-23 at 15 05 23

一応ドラッグすることで、キーボードで隠れてしまっている部分も操作することができますが、連絡先アプリ等を触ってみると、キーボード表示時には SectionIndexTitles が上にスライドしていることが分かります。

連絡先アプリ
Feb-23-2021 01-26-04

今回はこの挙動を目指して実装してみます。
また、以下のリポジトリにサンプルを作成したので、全体のコードが見たい方はそちらを参照してください🙇‍♂️

https://github.com/hayabusabusa/ZennSectionIndexTitlesSample

方針

キーボード表示のタイミングで TableView にキーボードの高さ分 contentInset を設けてあげることで、それっぽい動きを再現することができました。

final class ViewController: UIViewController {

    @IBOutlet private weak var tableView: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()

        // ...
        configureObserver()
    }

    private func configureObserver() {
      NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardWillShowNotification(_:)), name: UIResponder.keyboardWillShowNotification, object: nil)
      NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardWillHideNotification), name: UIResponder.keyboardWillHideNotification, object: nil)
    }

    @objc private func handleKeyboardWillShowNotification(_ notification: Notification?) {
        guard let rect = (notification?.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue else {
            return
        }
        UIView.performWithoutAnimation {
            self.tableView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: rect.height, right: 0)
            self.tableView.layoutIfNeeded()
        }
    }

    @objc private func handleKeyboardWillHideNotification() {
        UIView.performWithoutAnimation {
            self.tableView.contentInset = .zero
            self.tableView.layoutIfNeeded()
        }
    }
}

アニメーションをオフにしているのは、アニメーションありだと SectionIndexTitles が伸縮して若干気持ち悪かったのでオフにしています。
この実装で連絡先アプリと似たような挙動を再現することができました。

アニメーションなし アニメーションあり
Feb-23-2021 17-08-30 Feb-23-2021 17-09-33

他にも SectionIndexTitlesUITableView から生えている以下のプロパティで見た目等を調節することができます。

  • sectionIndexColor: 文字色
  • sectionIndexBackgroundColor: 通常時の背景色
  • sectionIndexTrackingBackgroundColor: トラッキング時の背景色
  • sectionIndexMinimumDisplayRowCount: いくつの要素があったときに sectionIndexTitles に項目を表示するか?( 指定しても特に変化がありませんでした🤔 )

さいごに

SectionIndexTitles に関しての情報は調べてもあまり出てこなかったので残しておきます。
この情報が誰かの助けになれば幸いです。

  • 20210312 追記

UITableViewController を使ってもう少し調べてみました。

https://zenn.dev/hayabusabusa/scraps/c40f007fd72dd3

Discussion