43
37

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 1 year has passed since last update.

UINavigationController 周りの表示・非表示設定まとめ

Last updated at Posted at 2019-01-11

Overview

毎度いろんな意味で今更という記事ですが、個人的には振り返りに使えるメモ。

今更ながら、iOS11 プログラミング をつらつら読み返していたところ、「レイアウト関連の新機能及び変更点」のところで、ナビゲーションバーを大きくしたり検索バーを付けたり折りたたんだりという設定を紹介しており、「iOS って昔から結構この辺の表示・非表示の切り替えが沢山あったけど、何があったかな〜」と回想してしまいました。一通りコーディングしてまとめたものを Github に載せておきました。

例えば、 UINavigationController.setNavigationBarHidden(true :, animated:true)を呼び出すとナビゲーションバーが隠れます。あるいは、 UINavigationController.hidesBarsOnTap = trueを選択してメインビューをタップすると、ナビゲーションバーと下部ツールバー(存在する場合)の両方が非表示になります。

例 :
hideBars.gif

以下、まとめ。ほぼ自明な機能ばっかりだけど、時々留意事項があるものもありました。

UINavigationController

setNavigationBarHidden(:, animated:)

navigationController?.setNavigationBarHidden(true、animated:true)を呼び出すことでナビゲーションバーを隠すことができます。

setToolBarHidden(:, animated:)

navigationController?.setToolbarHidden(true、animated:true)を呼び出すことで下部のツールバーを隠すことができます。

ただし、ツールバーはデフォルトで非表示になっているので、明示的に指定する必要はありません。ツールバーを表示するには、ツールバーに BarButtonItemsを設定する必要があります。例えば、

let actionItem = UIBarButtonItem(barButtonSystemItem: .action, target: nil, action: nil)
let spacerItem = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
let saveItem = UIBarButtonItem(barButtonSystemItem: .save, target: nil, action: nil)
toolbarItems = [actionItem, spacerItem, saveItem]

としてやります。

hidesBarsOnTap

navigationController?.hidesBarsOnTap = trueを設定した後にメインビューをタップすると、ナビゲーションバーとツールバーの両方が切り替わります。

hidesBarsOnSwipe

navigationController?.hidesBarsOnSwipe = trueを設定した後に画面の下から上にスワイプをすると、ナビゲーションバーとツールバーの両方が非表示になります。ただし、期待に反して、スワイプダウンをしてもバーは元に戻りません。すなわち一旦バーを隠すと、バーは二度と戻って来なくなります。これが期待通りの動作なのかiOSのバグなのかわかりませんが、これについて不満を言っているStackoverflow の投稿は結構あります。 例:https://stackoverflow.com/questions/32992897/hidesbarsonswipe-does-not-show-navigationbar-when-scrolling-up-to-the-top-slowly)

1つの回避策は、(スクロールビューとして UITableView を使っている場合)一番上の行が表示されたときにそれらを再度表示することです。

    func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
        if (indexPath.section == 0 && indexPath.row == 0) {
            navigationController?.hidesBarsOnSwipe = false
            navigationController?.setNavigationBarHidden(false, animated: true)
            navigationController?.setToolbarHidden(false, animated: true)
        } else {
            navigationController?.hidesBarsOnSwipe = true
        }
    }

hidesBarsWhenVerticallyCompact

navigationController?.hidesBarsWhenVerticallyCompact = trueを設定した後にデバイスを横向きに回転させると、ナビゲーションバーとツールバーの両方が隠れます。縦向きに戻すと元に戻ります。

hidesBarsWhenKeyboardAppears

navigationController?.hidesBarsWhenKeyboardAppears = trueを設定した後にキーボードを起動すると、ナビゲーションバーとツールバーの両方が非表示になります。しかし、期待に反して、キーボードを収納しても元には戻りません。このデモでは、 UITextFieldDelegate.textFieldShouldReturn(_ :)をキャプチャして手動でバーを元に戻します。

    navigationController?.setNavigationBarHidden(false, animated: true)
    navigationController?.setToolbarHidden(false, animated: true)

もう 1つの落とし穴は、このフラグを trueに設定すると、あとでフラグをfalseに設定した後も true である時の動作が持続することです。これはiOSのバグだと思いますが、このフラグを UIViewControllerの有効期間内に切り替えるのはあまり一般的ではないので、実際に問題になることはあまりないのでしょう。

また、 UINavigationItem.searchController を設定してナビゲーションバーの下に検索バーを実装した時は、このフラグを true に設定しないこと。何かを検索しようとすると、キーボードがポップアップして、ナビゲーションバーを隠しますが、検索バーもナビゲーションバーの一部なので、検索バー自体が見えなくなります。検索したいのに検索バーが見えないというよくわからない状態になってしまいます。このデモはサンプラーなのでこの禁忌を犯していて、おかしな挙動が見られます。

UINavigationBar

hidesSearchBarWhenScrolling

navigationItem.searchControllerを設定することで、検索バーをナビゲーションバーの下に実装していると仮定します。 navigationItem.hidesSearchBarWhenScrolling = trueを設定した後にスクロールビューを上にスクロールすると、ナビゲーションバーの下の検索バーは折りたたまれます。スクロールビューを下にスクロールすると、拡大して再び表示されます。デフォルト値は trueです。したがって、検索バーを常に保持したい場合は、逆にこれを falseに設定してください。

UISearchController

hidesNavigationBarDuringPresentation

navigationItem.searchControllerを設定することで、検索バーをナビゲーションバーの下に実装していると仮定します。 navigationItem.searchController.hidesNavigationBarDuringPresentation = trueを設定した後に検索バーをタップすると、ナビゲーションバーは非表示になり、検索バーのみが上部に表示されます。デフォルト値は trueですので、検索をしている間ナビゲーションバーをキープしたい場合は、逆にこれを falseに設定してください。

UIViewController

prefersStatusBarHidden

この computed variable をオーバーライドして true を返すと、ステータスバーは非表示になります。


var statusBarHidden = false

override var prefersStatusBarHidden: Bool {
    return statusBarHidden
}

...

    statusBarHidden = true
    setNeedsStatusBarAppearanceUpdate()

オーバーライドした computed variable を呼び出してレンダリングを行うためには setNeedsStatusBarAppearanceUpdate() を呼び出す必要があるというところは一つのポイントです。また、この設定は iPhone Xのような端から端までのデバイスでは動作せず、ステータスバーは常に表示されています。おそらく、そもそもノッチ領域にあるステータスバーを隠すのは意味がないということだと思います(ナビゲーションバーがノッチ領域と重なってしまうのでおかしな見栄えになる)

homeIndicatorAutoHidden

この computed variable をオーバーライドして true を返すと、iPhone X などの edge-to-edge のディスプレイで、ホームボタンの場所を示す細くて白いバーが消えます。


var homeIndicatorAutoHidden = false

override var prefersHomeIndicatorAutoHidden: Bool {
    return homeIndicatorAutoHidden
}

...

    homeIndicatorAutoHidden = true
    setNeedsUpdateOfHomeIndicatorAutoHidden()

オーバーライドした computed variable を呼び出してレンダリングを行うためには setNeedsUpdateOfHomeIndicatorAutoHidden()を呼び出す必要があります。

UINavigationBar

prefersLargeTitle

self.navigationController?.navigationBar.prefersLargeTitles = true としてスクロールビューを上にスクロールするとナビゲーションバーが小さくなり、下にスクロールするとナビゲーションバーが大きく表示されます。この動作は何かを隠しているという訳ではないけれども、類似の特筆すべき振る舞いとしてリストしました。

43
37
1

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
43
37

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?