noteタイトル01

SwiftUIの画面切替

驚くほどの少ないソースコードでUI画面を表示できるSwiftUIは、画面切替も独自です。この記事とサンプルを参考にしてください。

※この記事ではSwift言語(最新の5.1)の基本的な知識を前提にしています。コード内のキーワードや書式などの不明点は Swift5初級ガイドなどを参照してください。

※SwiftUIについて全体的なことは『SwiftUI最初の一歩』、コードの基本は『SwiftUIの文法 その1 View』を参照してください

毎月札幌でiOSアプリ作りをアシストするセミナーをやっています。1時間にわたるセミナーの全内容を、物理的に参加できない方のためにnote上で公開します。

お知らせ
電子書籍『Swift5初級ガイド』をAppleのブックストアから出しました。サンプルは無料です。MacでもiPadでもiPhoneでも読めます。
WWDC2020で発表されたSwift 5.3に対応した第6版がダウンロード可能です。(ご購入済みの場合は無料アップデートです)
ブックストアから一度購入すると今後のアップデートは無料で読めます。

6宣伝store

iOSアプリ作りをアシストするセミナーは今後も月一回のペースで続ける予定です。(2020年3月以降COVID-19感染拡大防止のため休止しています)
詳細は connpass.com の 札幌Swift でご確認ください。そして機会があればぜひ参加してください。
アプリ作りやプログラミング教育に関連する話題は 札幌Swift のfacebookページ で発信しています。

・画像クリックで拡大表示できます
・画像を拡大表示中は画像の左右をクリックで画像だけを順に表示できます
・ソースコード部分は左右にスクロールできます
Xcode は 11.3 を使っていています。
サンプルはすべてXcodeのiOS用プレイグラウンド書類用コードです。(iPadのPlaygroundsでも直接入力し実行できます)
この記事の最後の有料部分にあるリンクから完全なサンプルをダウンロードできます。


1 画面切替

画面の切替(画面遷移と呼ぶことも多い)はディスプレの小さなモバイルデバイスには必須の機能です。
画面の切替はアニメーションで「何が起きたのか」操作者に伝えます。
最も多く利用されるアニメーションは行末から画面がせり出して切り替わるものと、下からせり出すものです。

画面切替に関係する各OSのヒューマンインターフェイスガイドライン(HIG)を参考にしてください(英文サイトです)。
ここではiOS用にリンクしています。

Navigation

Modality

Navigation Bars

Alerts


2 ナビゲーションビュー

SwiftUIでは NavigationView 型が画面切替の起点です。
SwiftUIのドキュメントでは View Layout and PresentationArchitectural Views に分類されています。

NavigationViewのドキュメントには『ナビゲーション階層の可視パスを表すビューのスタックを表示するためのビュー。』とあります。
NavigationView 単体では上部にナビゲーションバー を持つだけですが、後で説明するナビゲーションリンクを使って画面切替を実現します。

最初のサンプルはシンプルなリストにナビゲーションバーを付けたものです。

// サンプル 01-50
import SwiftUI
import PlaygroundSupport

struct Sample01View: View {

  var body: some View {
     NavigationView {
        List {
           Text("001")
           Text("002")
        }
        .navigationBarTitle("ナビゲーションビュー")
     }
     
  }
}

// playgroundで実行する場合に必要なコード
PlaygroundPage.current.liveView = UIHostingController(rootView: Sample01View())

Xcodeでの実行画面

画像2

このサンプルでは NavigationViewの中に表示する2行だけの List をレイアウトしています。
NavigationViewのイニシャライザは次のひとつだけです。

// NavigationViewのイニシャライザ
init(@ViewBuilder content: () -> Content)

引数はひとつで表示するビューを指定します、SwiftUIでは通常トレイリングクロージャで書きます。

ただしNavigationViewだけではナビゲーションバーには何も表示されません。
ナビゲーションバーのタイトルなどをモディファイアで追加すると、見慣れたナビゲーションバーにタイトルを表示します。

2-1 ナビゲーションバータイトル

ナビゲーションバーの表示はViewプロトコルのモディファイアを使います。
navigationBarTitle(_:) でタイトルを表示します。
サンプルのようにナビゲーションビューの中身(このサンプルではListのイニシャライザ)に .navigationBarTitle("ナビゲーションビュー") モディファイアを書きます。

2-2 navigationBarTitle(_:)

最初のサンプルで使っていた navigationBarTitle(_:) ではタイトルは大きく表示し上スクロールでナビゲーションバーの高さが小さくなります。

// ナビゲーションバー シンプル版
func navigationBarTitle<S>(_ title: S) -> some View where S : StringProtocol
func navigationBarTitle(_ title: Text) -> some View

引数に渡すタイトルは文字列とText型のインスタンスの二つがあります。

2-3 navigationBarTitle(_:displayMode:)

navigationBarTitle(_:displayMode:) モディファイアは二つの引数を持ちます。

// displayMode指定付きナビゲーションバー
func navigationBarTitle(_ title: Text, 
displayMode: NavigationBarItem.TitleDisplayMode) -> some View

最初の引数は通常のタイトルのText型インスタンスです。
二つ目の displayMode: はタイトルの表示方法を指定します。
現在三つの方法が定義されています。

NavigationBarItem.TitleDisplayMode.inline
ナビゲーションバーの標準範囲内にタイトルを表示します。
サンプルの 01-52 です。

画像20

NavigationBarItem.TitleDisplayMode.large
展開されたナビゲーションバー内に大きなタイトルを表示します。
displayModeを指定しない場合はこの設定になります。
サンプルの 01-51 です。

画像20

NavigationBarItem.TitleDisplayMode.automatic
前のナビゲーション項目から表示モードを継承します。(画面割愛)


3 ナビゲーションリンク

SwiftUIの画面切替はボタンを使い宣言型に書きます。
専用のボタンが NavigationLink です。

WWDC2019のセッション216ではNavigationButtonと呼ばれていましたが、現在では NavigationLink となっています。
NavigationLink はボタンの一種でViewプロトコルに準拠しているstructです。
SwiftUIのドキュメントでは Views and Controls > Buttons に分類されています。

NavigationLink は押されたときにナビゲーションプレゼンテーションをトリガーするボタンです。
NavigationView 内にある NavigationLink だけが画面遷移を開始します
NavigationView の中にない場合は NavigationLink を押しても(タップしても)画面は切替りません。

NavigationLink にはイニシャライザが12もあります。
ここでは最も基本的なinit(destination:label:)だけを説明します。

3-1 init(destination:label:)

引数を二つ持つイニシャライザです。
一つ目の引数が切り替わった後の画面を指定します。
二つ目の引数はナビゲーションリンクのラベルの指定です。
普通はトレイリングクロージャで書くため  NavigationLink(destination: ...) { ... } とdestination:引数ひとつだけに見えます。

NavigationLinkをViewのbodyに書くのもSwiftUIの特徴です。

サンプル 01-53

// サンプル01-53
import SwiftUI
import PlaygroundSupport

struct DetailView: View {
  var body: some View {
     VStack {
        Text("Detail")
           .font(.title)
        Text("切替で表示する画面")
           .padding()
     }
     .navigationBarTitle("第二面",
                    displayMode: .inline)
  }
}

struct Sample01View: View {

  var body: some View {
     NavigationView {
        List {
           NavigationLink(destination: Text("1行目をタップした")) {
              Text("001")
           }
           NavigationLink(destination: DetailView() ) {
              Text("002")
           }
        }.navigationBarTitle("項目を選択")
     }
  }
}

// playgroundで実行する場合に必要なコード
PlaygroundPage.current.liveView = UIHostingController(rootView: Sample01View())

NavigationLinkもビューなので Listの一行目が画面切替で Text を表示する次のコード

           NavigationLink(destination: Text("1行目をタップした")) {
              Text("001")
           }

二行目が画面切替で DetailView を表示する次のコード

           NavigationLink(destination: DetailView() ) {
              Text("002")
           }

です。

実行画面

画像20

各行の右側に > を表示し画面が切り替わることを示します

このサンプルの一行目をタップして切り替わる画面は Textのインスタンスのみです。
ナビゲーションバー部分に前の画面に戻るためのボタンを自動表示します。

画像20

二行目をタップすると DetailView を表示します。
ナビゲーションバー 部分に前の画面に戻るためのボタンを自動表示は同じです。
navigationBarTitleメソッドで設定したタイトル(第二面)を表示します。

画像20

通常は切り替える画面をこのように独立したビューとして宣言し指定します

NavigationLinkのイニシャライザ

// NavigationLinkの代表的イニシャライザ
init(destination: Destination, 
@ViewBuilder label: () -> Label)

Destination 型と Label 型はそれぞれ View 型です。

実行するとXcodeのプレイグラウンドとiPadのPlaygroundsアプリでは結果が変わります。

XcodeではiPhoneの画面に相当する画面が(Textがひとつの)destination画面に完全に覆われます。
切替後の画面(destination)にもナビゲーションバー があり、戻るためのボタンがデフォルトで表示され、タップ操作で戻ります。

画像20

iPadのPlaygroundsではSplit Viewのような表示にdestinationが並びます。
(iPadを縦にしてライブビューだけをキャプチャーしています)

画像17

続きをみるには

残り 9,438字 / 12画像 / 1ファイル
この記事のみ ¥ 500
期間限定 PayPay支払いすると抽選でお得に!

今後も記事を増やすつもりです。 サポートしていただけると大変はげみになります。