6
4

More than 3 years have passed since last update.

SwiftUI 全画面でホームバーを隠す

Last updated at Posted at 2019-11-21

SwiftUIで全画面時にHomeIndicatorを隠したい

SwiftUIではUIViewControllerを直接制御しないため、HomeIndicatorを非表示にする際に、prefersHomeIndicatorAutoHiddenメソッドを設定することができません。今のところはSwiftUIのContentView上でもpreferenceに設定が無いようなので、自前のクラスを挟んで制御するようにしてみました。

記述を簡略化できました。

SceneDelegateの起動設定を確認

iOS13から導入されたSceneDelegateにより、プロジェクト内の構成が変わっており、内部的にはSceneDelegateクラスのscene(_ ,willConnectTo: 〜〜〜)メソッドでrootViewControllerを指定するようになっています。

image.png

これを以下のように切り替えるイメージです。

image.png

今回はホームバーの制御を目的にしていますが、UIViewControllerを利用したその他の設定にも活用できると思います。

設定の流れ

この起動の流れに対して、rootViewControllerにカスタムクラスを設定することでホームバーの非表示にしてみます。

  1. カスタムクラス(HomeIndicatorHiddenHostingController)の作成
  2. (カスタムクラスにホームバー制御のメソッドを追加)
  3. SceneDelegateでカスタムクラスを指定

基本的にこのような流れで設定します。

1. カスタムクラス(HomeIndicatorHiddenHostingController)の作成

もともと使用されているUIHostingControllerクラスを継承したカスタムクラスを作成します。

HomeIndicatorHiddenHostingController.swift
class HomeIndicatorHiddenHostingController<Content>: UIHostingController<Content> where Content: View  {
    override var prefersHomeIndicatorAutoHidden: Bool {
        return true
    }
}

2.(カスタムクラスにホームバー制御のメソッドを追加)

以下のメソッドの戻り値でホームバー(HomeIndicator)をHiddenに設定するようにしています。正確には、表示されなくなるわけではなく一定時間経つと見えなくなります(触れば再表示される)。

init
    override var prefersHomeIndicatorAutoHidden: Bool {
        return true
    }

ここではhiddenに固定していますが、動的に設定を切り替えたい場合には、setNeedsUpdateOfHomeIndicatorAutoHidden()メソッドも利用する必要があります。
参考:https://dev.classmethod.jp/smartphone/iphone/iphone-x-dealing-with-home-indicator/

3. SceneDelegateでカスタムクラスを指定

SceneDelegateのrootViewController指定で、カスタムクラスを利用します。

SceneDelegate.swift
    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        let contentView = ContentView()

        if let windowScene = scene as? UIWindowScene {
            let window = UIWindow(windowScene: windowScene)
            window.rootViewController = HomeIndicatorHiddenHostingController(rootView: contentView)
            self.window = window
            window.makeKeyAndVisible()
        }
    }

以上の流れで、SwiftUIのContentViewを表示している際にもホームバーが隠れるようになると思います。

未解決:UIHostingController継承時の書き方 → 解決済み

うまく調べきれず親クラスであるUIHostingControllerの初期化部分の指定をAnyViewとする方法しかわからなかったので、改善の余地があるかと思います。

Swift5.1から導入されたOpaque Result Type(where 句)を利用することで型を制限せずSwiftUIのViewプロトコルに準拠したいずれかのViewクラスをContentとしてラップしたもの、という表現をすることができました。初期化がごっそり減ったのでだいぶ使いやすいと思います。

【SwiftUI を理解するために必要な Swift 5.1 の新機能 (some View編)】
https://speakerdeck.com/kumamotone/swiftui-woli-jie-surutamenibi-yao-na-swift-5-dot-1-falsexin-ji-neng-some-viewbian?slide=41

【Opaque Result Typeの解説】
https://qiita.com/omochimetaru/items/f13fe3e54fab01648ba4

未解決時のコード

HomeIndicatorHiddenHostingController.swift
class HomeIndicatorHiddenHostingController: UIHostingController<AnyView> {
    init<V: View>(rootView: V) {
        super.init(rootView: AnyView(rootView))
    }
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
    override var prefersHomeIndicatorAutoHidden: Bool {
        return true
    }
}

解決済のコード

HomeIndicatorHiddenHostingController.swift
class HomeIndicatorHiddenHostingController<Content>: UIHostingController<Content> where Content: View  {
    override var prefersHomeIndicatorAutoHidden: Bool {
        return true
    }
}

参考

「How to hide the home indicator with SwiftUI?」
https://stackoverflow.com/questions/56795572/how-to-hide-the-home-indicator-with-swiftui
【随時更新】iPhoneX完全対応マニュアル
https://qiita.com/cokaholic/items/6a8ee3852c8ed28ea2aa

6
4
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
6
4