10
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

UINavigationBarをスクロールで表示/非表示させる方法【TableView】【ライブラリなし】

Last updated at Posted at 2018-09-28

要件(ゴール)

・tableViewで一覧から詳細へ遷移できる
・一覧で下へスクロールした際はNavigationBarを非表示/上へスクロールした際はNavigationBarを表示
・詳細ではNagigationBarを隠さない
・詳細から一覧へ戻った際は、NavigationBarの表示/非表示の状態が維持されている

背景

http://animane.hatenablog.com/entry/2016/02/04/144458
で紹介されているようなライブラリもあるのだが、
いざプロジェクトに組み込んで見ると、思うような挙動にならなかったり、
swiftにそもそも対応してなかったりした。
調べてみると自力で実装でもそんなに大変ではなさそうなので、
実装してまとめて記事にしました。

環境

OS: iOS9~iOS12まで確認済
言語:Swift4.2

前提

tableViewで一覧から詳細へ遷移できるプロジェクトがあること

サンプルプロジェクト

こちらを手元で確認していただけながら、読み進めていただければと思います。
https://github.com/suzuhiroruri/scrollHidingNavbar

手順

下記変数を入れる

MasterViewController.swift
///  スクロール開始地点
var scrollBeginPoint: CGFloat = 0.0

/// navigationBarが隠れているかどうか(詳細から戻った一覧に戻った際の再描画に使用)
var lastNavigationBarIsHidden = false

スクロール開始時にスクロール開始地点を習得

MasterViewController.swift
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
    scrollBeginPoint = scrollView.contentOffset.y
}

scrollViewDidScrollでスクロール量を検知
MasterViewController.swift
func scrollViewDidScroll(_ scrollView: UIScrollView) {
    let scrollDiff = scrollBeginPoint - scrollView.contentOffset.y
    updateNavigationBarHiding(scrollDiff: scrollDiff)
}

navigationBarの表示/非表示を更新メソッド boundaryValueはスクロールの閾値なのでお好みで設定してください。
MasterViewController.swift
func updateNavigationBarHiding(scrollDiff: CGFloat) {
    let boundaryValue: CGFloat = 0.0

    /// navigationBar表示
    if scrollDiff > boundaryValue {
        navigationController?.setNavigationBarHidden(false, animated: true)
        lastNavigationBarIsHidden = false
        return
    }

    /// navigationBar非表示
    if scrollDiff < -boundaryValue {
        navigationController?.setNavigationBarHidden(true, animated: true)
        lastNavigationBarIsHidden = true
        return
    }
}

詳細画面から戻ってきた際にNavigationBarの表示状態を以前の状態に更新
MasterViewController.swift
override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    if lastNavigationBarIsHidden {
        self.navigationController?.setNavigationBarHidden(true, animated: false)
    }
}

デフォルトだと詳細遷移の際、NavigationBarが非表示になってしまうので、表示させる

MasterViewController.swift
override func viewDidLoad() {
    super.viewDidLoad()
    navigationController?.setNavigationBarHidden(false, animated: false)
}

tableViewのTopをSafeAreaに設定するとiOS10系の端末でtableの表示がずれてしまう場合があるので、 topをViewのTopにする。 またそれだとiPhoneX系の端末でtableViewをスクロールした時にSafaAreaにかぶるので、 SafeAreaを隠すビューを入れる。 ![スクリーンショット 2018-09-28 17.19.59.png](https://qiita-image-store.s3.amazonaws.com/0/13599/a053763c-f613-ba26-08c0-dcab1b5aa6c5.png)

あとがき

navigationController?.hidesBarsOnSwipe = true

https://qiita.com/ken0nek/items/9e293bd7d730191cdbc5
で動かないこともないんですけど、
微妙なスクロールだとSwipeと検知されないこともあったり、
OS?機種?によってNavigationBarが表示できないこともあったので、
今回はスクロールベースで検知してNavigationBarの表示を切り替えるようにしました。
訂正等ありましたら、よろしくお願いします。

10
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?