iPhone XS Max/XR と iPhone XSではランドスケープ時のUISplitViewControllerの挙動が異なります
はじめに
ついにiOS 12 そして Xcode 10が正式にリリースされましたね。そして先日iPhone XS/XS Max/XRなど新製品の発表もありました。 これに伴い、Appleが新たにBuilding Apps for iPhone XS, iPhone XS Max, and iPhone XRというビデオを公開しています。 このビデオの中で、iPhone XS Max/XRの画面サイズへの対応方法やiOS 12でのAutoLayoutのパフォーマンスアップなどについて説明があるのですが、UISplitViewControllerについてもXS Max/XR とXSで挙動が異なる部分があったので記事にしたいと思います。
検証環境
本エントリは以下の環境で検証を行っています。
- macOS High Sierra バージョン 10.13.6
- Xcode Version 10.0 (10A255)
- iPhone XS Max iOS 12.0 シミュレーター
- iPhone XS iOS 12.0 シミュレーター
- Apple Swift version 4.2 (swiftlang-1000.11.37.1 clang-1000.11.45.1)
違いはMaster-Detail Appのプロジェクトテンプレートですぐに確認できます
UISplitViewControllerの挙動の違いについてはXcode 10でiOS > Master-Detail Appのプロジェクトテンプレートから新規プロジェクトを作成すればすぐに確認できます。
ご覧の通り、ランドスケープ時の画面の表示が違いますね。 iPhone XS Maxの方は画面左上のボタンをタップするとMaster画面が左からDetail画面に重なる形で表示されます(iPhone XRも同じ挙動でした)。さらに画面左端をスワイプしても画面を表示できます。 一方、XSの方は一度に1つの画面のみ表示されています。
コードはどうなっているか
コードはどうなっているか見てみましょう。AppDelegateでアプリ起動時にnavigationItem.leftBarButtonItem
にsplitViewController.displayModeButtonItem
を設定しています。これによりXS Max/XRではMaster画面を左から表示するボタンを表示しています。
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { let splitViewController = window!.rootViewController as! UISplitViewController let navigationController = splitViewController.viewControllers[splitViewController.viewControllers.count-1] as! UINavigationController navigationController.topViewController!.navigationItem.leftBarButtonItem = splitViewController.displayModeButtonItem splitViewController.delegate = self return true }
挙動を変えてみる
プロジェクトを作成した直後は上記のような実装になっていますが、Master画面を左から表示するボタンは表示したくない、画面左端スワイプによる画面表示をしたくない場合もあるでしょう。 その場合は以下のようにコードを変更します。
// displayModeButtonItemを使っている部分を削除(コメントアウト) //let navigationController = splitViewController.viewControllers[splitViewController.viewControllers.count-1] as! UINavigationController //navigationController.topViewController!.navigationItem.leftBarButtonItem = splitViewController.displayModeButtonItem // スワイプによるMaster画面表示を禁止 splitViewController.presentsWithGesture = false
この場合のXS Max/XRでの実行結果は以下になります。
なぜランドスケープ時の画面の表示が違うのか
なぜ、iPhone XS Max/XRは一度に2画面表示され、XSは1画面のみ表示されるのでしょうか。
実はこちらの記事にもあるように過去にはiPhone 6+などもランドスケープ時はiPadのように2画面表示でした。そしてその理由は、iPhone 6+のランドスケープ時のSize ClassのWidthがiPad 同様にRegularになっていたためでした。
そこで今回もSingle View Appを作成し、以下のようにtraitCollectionDidChange(_:)
メソッドをオーバーライドして各デバイスのSize Classを取得してみました。
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { let horizontalSizeClass = traitCollection.horizontalSizeClass let verticalSizeClass = traitCollection.verticalSizeClass print("--- H ---") switch horizontalSizeClass { case .unspecified: print("unspecified") case .compact: print("compact") case .regular: print("regular") } print("--- V ---") switch verticalSizeClass { case .unspecified: print("unspecified") case .compact: print("compact") case .regular: print("regular") } }
まとめると結果は以下の通り。やはりランドスケープ時のSize ClassのWidthがXS MaxとXRではRegularになっていました。ということで2画面表示も納得ですね( ´◡` )
Portrait - Width | Portrait - Height | Landscape - Width | Landscape - Height | |
---|---|---|---|---|
iPhone XS | Compact | Regular | Compact | Compact |
iPhone XS Max | Compact | Regular | Regular | Compact |
iPhone XR | Compact | Regular | Regular | Compact |
おわりに
今回はiPhone XS Max/XR と iPhone XSでのランドスケープ時のUISplitViewControllerの挙動・表示の違いをご紹介しました。 ランドスケープでUISplitViewControllerを使ってアプリを開発する場合はこの違いを認識しておきましょう!