iPhoneXから表示されるHome Indicatorの表示/非表示をViewController毎に設定したい
ちょいとこのHome Indicatorを隠したい要件があって、まだ世の中にHome Indicatorの記事出回ってないようなのでメモ。
Home Indicatorとは
iPhoneXの画面下部に表示されるバー。この辺のiPhoneX画像見てもらうとありますよねー。
https://developer.apple.com/ios/human-interface-guidelines/overview/iphone-x/
iPhoneXからは物理ホームボタンがなくなって、画面下部からのスワイプ操作でホーム画面に戻すので、その操作を連想させるための画面コントロールらしい。
UIViewControllerでの表示制御方法
Home Indicatorの表示制御はUIViewControllerの以下の2つのメソッドで行う。
func prefersHomeIndicatorAutoHidden() -> Bool
- そのViewControllerでのHome Indicator表示/非表示を定めるメソッド。デフォルトは
false
(Home Indicator表示させる)
func childViewControllerForHomeIndicatorAutoHidden() -> UIViewController?
- そのViewControllerでのHome Indicator表示/非表示を 子のViewControllerに委託 するメソッド。デフォルトは
nil
nil
を返却すると、表示/非表示は自ViewController内のprefersHomeIndicatorAutoHidden()
の値に従う- 子ViewControllerを返却すると、表示/非表示は返却したViewController内の
prefersHomeIndicatorAutoHidden()
の値に従う
基本的には任意のViewControllerでprefersHomeIndicatorAutoHidden()
をオーバーライドし、そこで任意のBool値を返却することで表示制御を行うこととなる。
コンテナ型ViewController使用時の注意点
複数のViewControllerを統合して1つのUIとして形成されているコンテナ型のViewController(ex. UINavigationController, UITabBarController, UISplitViewController, etc...)の場合、Home Indicatorの表示制御は最初に親となるViewControllerに委託される。
親ViewControllerで特に何も設定していない(デフォルト値の)場合、子ViewControllerでの表示制御は親ViewControllerの設定が引き継がれるため、Home Indicatorは「表示」設定となり、子ViewControllerでprefersHomeIndicatorAutoHidden()
をtrue
(非表示)に設定してもこのメソッド自体呼ばれない。
子ViewControllerにHome Indicatorの表示制御を委託
子ViewControllerにHome Indicatorの表示制御を委託したい(≒Home Indicatorの表示/非表示を子ViewController毎に決めたい)場合は、以下のように設定する。
例)UINavigationControllerを使用中の場合
親ViewController側の設定
// ExtensionでUINavigationControllerに一律設定する場合 extension UINavigationController { override func childViewControllerForHomeIndicatorAutoHidden() -> UIViewController? { // 表示制御を委託したいViewController(この例では現在NavBar表示中のViewController)を指定 return self.visibleViewController } }
// 既にUINavigationControllerを継承したカスタムクラスがある場合 class CustomNavigationController: UINavigationController { ... override func childViewControllerForHomeIndicatorAutoHidden() -> UIViewController? { return self.visibleViewController } }
子ViewController側の設定
class ChildViewController: UIViewController { ... override func prefersHomeIndicatorAutoHidden() -> Bool { return true // true: 非表示, false: 表示 } }
ちなみに親子関係がもっと深い場合は、その分だけ子への表示制御委託を繰り返す必要があるみたい。
おわりに
今時はTabBarやNavigationBar使ってるアプリがほとんどだと思うんで、非表示にする必要があるならこの委託処理は必須なのでは。
あ、ちなみに「委託」という言葉はなんとなくイメージで使っているだけで、この言葉で合ってるのかは不明。「移譲」だとデリゲートみたいに聞こえちゃうので。