UIViewControllerをオーバレイ表示させる
Dec 7, 2017 · iosswift3
概要
UIViewController
をUIAlertController
みたいに表示させるのをStoryboard
で実現する方法
例えば、くるくるとインジケータを回したい画面をオーバレイで表示させたい時とかに使える
メリット
古い時代の実装だと、画面はnibで作るかコードで実装、表示させたい時にaddSubview
していた分だが、
こちらの方がいろいろとメリットが大きい
ざっと思いつくだけでも、
ViewController
が持てるのでライフサイクル周りのイベントが取れる- 他の
ViewController
、特にUIAlertController
と同じ様に扱えるので便利で判りやすい AutoLayout
が使える(自分で実装しなくて良い)- 書くコードの量が減る
- 標準の手法である
といったあたり
(よくStoryboard
を覚えるのが大変だから、コードで実装した方が良い派がいるけど、個人的にはどう考えても
UIViewController
が中でやっているライフサイクルの管理やAutoLayout
等を全部、
しかも各OSのバージョン毎に覚えて実装してテストする方が大変だと思う)
作り方
表示したい画面を作る
通常の画面と同じ要領で表示したいViewController
を作る
この時、本来のアプリの画面で使うStoryboard
とは別のStoryboard
で作成しておくと、
nib
ファイルみたいに他のプロジェクトで使い回すことも容易になるのでオススメ
(これに限らず、Storyboard
はこまめに分割しておくとコンフリクトも起こりにくくなるので良い)
作成できたら、以下の設定を行う
ViewController
のViewのBackground
を 半透明 で設定する- 透過させたくないViewは
Opaque
にチェックを入れる ViewController
のTransition Style
をCross Dissolve
に設定する(※)
(画面を表示する際のアニメーション。通常だと違和感があるのでこれに変える)ViewController
のPresentation
をOver Full Screen
に設定する(※)
※:もし、後述のセグエを使って表示しか使わない場合は設定不要(セグエでの設定が優先されるため)
例
インジケータを表示させるIndicatorViewController
を作りたい場合、、、
画面イメージとしては、ボタンのないUIAlertController
の様に画面中央に白いViewがあり、その上にUIActivity
が載っている状態。また、画面中央の白いView以外の部分は黒の半透明で、元のViewController
が表示されている
この場合は白いViewのOpaque
にチェックを入れる
表示させる
大きく分けると、
- セグエを使って表示
present
を使って表示
の2つになる
セグエを使う
データの受け渡しが面倒なのと、そもそもモーダル表示を他の画面遷移と同列に扱うのか?といったあたりがあるので、あまり使わない方法
基本的には通常の画面遷移と同じ。
(専用のStoryboard
に作った場合は、Storyboard Reference
を使う)
セグエの設定ポイントは、
Kind
をPresent Modally
に設定するPresentation
をOver Full Screen
に設定するTransition Style
をCross Dissolve
に設定する
(画面を表示する際のアニメーション。通常だと違和感があるのでこれに変える)
である。この設定にするとUIAlertController
に似た表示のされ方となる
コードから呼び出す
例のインジケータを表示させるIndicatorViewController
の場合だと、生成するコードは、
static func instantiate() -> IndicatorViewController {
let storyboard = UIStoryboard(name: 作成したストーリーボード名, bundle: nil)
return storyboard.instantiateViewController(withIdentifier: ストーリーボード上のID) as! IndicatorViewController
}
となり、IndicatorViewController
のクラスメソッドとしておく
使う時は、
let indicator = IndicatorViewController.instantiate()
present(indicator, animated: true)
とすれば表示される
表示元のViewController
から閉じたい場合は、
presentedViewController?.dismiss(animated: true)
の1行で閉じても良いし、先ほどの生成したIndicatorViewController
を保持してdismiss
しても良い
開発環境
- Xcode 9.1
- iOS 11.1