Xcode
iOS
Swift
swift4

UITableViewの上部にsearchBarを固定する方法

はじめに

tableViewにsearchBarを追加し、スクロールすると普通はsearchBarが隠れてしまうと思います。
しかし、この設定だとユーザーがsearchBarを用い、新たに検索をしたいとなった時に、tableViewを上部までスクロールしないといけません。
これは結構不便ですよね?
今回はその改善策について書いていこうと思います。

よくある実装

よくある実装では、searchBarが隠れてしまっています。

よくある実装2.gif

改善した実装

改善した実装では、searchBarが隠れることなく常に表示されています。

完成形動画2.gif

開発環境

  • Xcode9
  • Swift4
  • iOS 10.0

実装方法

実装方法について触れていきたいと思います。
よくある実装は、tableViewのheaderViewにsearchBarを追加することによって実現しています。
逆に改善した実装は、tableViewのsectionViewにsearchBarを追加することによって実現しています。

tableViewのsectionには、tableViewの上部に固定されるという仕組みがあります。
その仕組みを用いて、実装していきます。
※tableViewのstyleがplainの時に限り、tableViewの上部に固定されます。groupedの場合は固定されません。

TableViewController.swift
import UIKit

class TableViewController: UITableViewController {

    let array:[String] = ["東京スカイツリー","東京タワー","東京駅","歌舞伎座","築地市場","皇居","雷門","国会議事堂","両国国技館","レインボーブリッジ","お台場海浜公園","フジテレビ本社ビル","東京ドームシティ","大江戸温泉物語","浅草花屋敷","すみだ水族館","上野動物園","アクアパーク品川","渋谷109"]

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    //section使う時に必須のメソッド
    override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return ""
    }

    override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        let searchBar = UISearchBar()
        searchBar.placeholder = "観光地を入力してください"
//        search.delegate = self //これを書かないとsearchButtonClickedとかのdelegate動かない
        return searchBar
    }

    //searchBarの幅に合わせる為に必要な処理
    override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
        return 44
    }

    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return array.count
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        cell.textLabel?.text = array[indexPath.row]
        return cell
    }
}

このようにして実装することができます!

最後に

自分はこの実装が施されたアプリを見て、どのような仕組みで実装しているのか分からず、結構悩んでいたので、自分と似た人の役に立てればなと思います!