前節ではデータとViewを独立させ, 繰り返し処理(Foreach)を使ってデータの数の分だけリストを作ることを行いました。データは 構造体 でわかりやすく整理した上で配列に必要な分だけデータを追加することができるようになりました。今節では前節のデータ構造を用いながら,2-1節で触れた画面遷移を連携させていきます。
-
SFSwiftUI02-5.swiftpm を開く
(サンプルコード)
- 中身が2-4を終えた段階と同じであることを確認する
-
MyApp.swiftを開き, NavigationStack を追加, ContentViewを包む
コード1#
1
2
3
4
5
6
7
8
9
10
11
12
13
|
import SwiftUI
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
NavigationStack {
ContentView()
.preferredColorScheme( .light )
}
}
}
}
|
次にContentViewのナビゲーション設定を行います。
- ContentView.swiftを開き, Listに .navigationTitle を追加する
コード2#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
import SwiftUI
struct ContentView: View {
var photos:[PhotoData] = [
PhotoData( type:"景色", imageName:"CC0_01", title:"景色1", message:"森と山です" ),
PhotoData( type:"景色", imageName:"CC0_04", title:"景色2", message:"きれいな湖です" ),
PhotoData( type:"景色", imageName:"CC0_06", title:"景色3", message:"フィレンツェです" ),
PhotoData( type:"景色", imageName:"CC0_07", title:"景色4", message:"ひまわりです" ),
PhotoData( type:"景色", imageName:"CC0_10", title:"景色5", message:"海に日が沈みます" ),
PhotoData( type:"食べ物", imageName:"CC0_05", title: "ハンバーガーセット", message: "おいしいです" ),
PhotoData( type:"食べ物", imageName:"CC0_08", title: "カフェラテ", message: "おちつきます" ),
PhotoData( type:"食べ物", imageName:"CC0_09", title: "ケーキ", message: "あまいです" ),
PhotoData( type:"食べ物", imageName:"CC0_12", title: "お酒", message: "酔います" )
]
var body: some View {
List {
Section( "景色写真" ) {
ForEach( photos.filter { $0.type == "景色" } ) { photo in
SceneryRow( data:photo )
}
}
Section( "食べ物写真" ) {
ForEach( photos.filter { $0.type == "食べ物" } ) { photo in
FoodAndDrinkRow( data:photo )
}
}
}
.listStyle( .grouped )
.navigationTitle( "写真集" )
}
}
|
結果1#
コード1のMyAppでコード2のContentViewをNavigationStackでつつんだため, 画面の上部に
大きなタイトルが表示されるようになります。ここまでで2-4で作ったのと同じリスト画面を再構築できました。
次に, 景色リストをタップした時に表示する詳細情報の画面を作ります。
- 新しくFileを追加, SceneryDetail.swiftに名前を変更
- PhotoData構造体を受け取れるようdataを用意
- dataの中身をViewの表示の.navigationTitle, Image, Textで使用する
コード3#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
import SwiftUI
struct SceneryDetail : View {
var data:PhotoData
var body: some View {
VStack {
Image( data.imageName )
.resizable()
.scaledToFit()
.padding( .bottom, 20 )
Text( data.message )
Spacer()
}
.padding()
.navigationTitle( data.title )
}
}
|
作成したSceneryDetailは景色リストを押した時の詳細画面です。dataに情報を渡して使います。SceneryDetailができたら, ContentViewに戻りSceneryDetailへの遷移を作ります。
- ContentView.swiftを再び開き, 景色写真のSceneryRowをNavigationLinkで包む
- SceneRowはタップすると画面遷移できる要素になる
- NavigationLinkの使い方はButtonと同様. actionが処理, labelが見た目
コード4#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
struct ContentView: View {
var photos:[PhotoData] = [
PhotoData( type:"景色", imageName:"CC0_01", title:"景色1", message:"森と山です" ),
PhotoData( type:"景色", imageName:"CC0_04", title:"景色2", message:"きれいな湖です" ),
PhotoData( type:"景色", imageName:"CC0_06", title:"景色3", message:"フィレンツェです" ),
PhotoData( type:"景色", imageName:"CC0_07", title:"景色4", message:"ひまわりです" ),
PhotoData( type:"景色", imageName:"CC0_10", title:"景色5", message:"海に日が沈みます" ),
PhotoData( type:"食べ物", imageName:"CC0_05", title: "ハンバーガーセット", message: "おいしいです" ),
PhotoData( type:"食べ物", imageName:"CC0_08", title: "カフェラテ", message: "おちつきます" ),
PhotoData( type:"食べ物", imageName:"CC0_09", title: "ケーキ", message: "あまいです" ),
PhotoData( type:"食べ物", imageName:"CC0_12", title: "お酒", message: "酔います" )
]
var body: some View {
List {
Section( "景色写真" ) {
ForEach( photos.filter { $0.type == "景色" } ) { photo in
NavigationLink( destination:{
SceneryDetail( data:photo )
},
label: {
SceneryRow( data:photo )
})
}
}
Section( "食べ物写真" ) {
ForEach( photos.filter { $0.type == "食べ物" } ) { photo in
FoodAndDrinkRow( data:photo )
}
}
}
.listStyle( .grouped )
.navigationTitle( "写真集" )
}
}
|
景色リストを選択した時, 選んだ情報(photo)をdataに渡して, SceneryDetail画面を作成します。タップすると画面が切り替わります。
結果2#
タップ前#
景色写真のリストをタップ後#
続けて, 食べ物写真の詳細画面も作成します。作り方は景色写真の詳細画面と同じです。
- 新しくFileを追加, FoodAndDrinkDetail.swiftに名前を変更
- SceneryDetailと少しView要素を変えた画面にする
- .font( .title2 ) : .title, .title2, .title3 を指定すると標準の章節項のサイズが使える
コード5#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
import SwiftUI
struct FoodAndDrinkDetail : View {
var data:PhotoData
var body: some View {
VStack( alignment:.leading ) {
ZStack( alignment: .bottomTrailing ) {
Image( data.imageName )
.resizable()
.scaledToFit()
VStack {
Text( data.title )
.font( .system(size: 24.0) )
.foregroundStyle( .white )
.padding()
}
}
VStack( alignment:.leading ) {
Text( "食べ物の紹介" )
.font( .title2 )
.padding( .bottom )
Text( data.message )
.font( .system(size: 14.0 ) )
}
.padding()
Spacer()
}
.navigationTitle( data.title )
}
}
|
これも景色写真と同様にContentViewの食べ物写真にNavigationLinkを追加します。
- ContentView.swiftを再び開き, 食べ物写真のFoodAndDrinkRowをNavigationLinkで包む
- SceneryRowと同様, FoodAndDrinkRowが画面遷移できる要素になる
コード6#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
struct ContentView: View {
var photos:[PhotoData] = [
PhotoData( type:"景色", imageName:"CC0_01", title:"景色1", message:"森と山です" ),
PhotoData( type:"景色", imageName:"CC0_04", title:"景色2", message:"きれいな湖です" ),
PhotoData( type:"景色", imageName:"CC0_06", title:"景色3", message:"フィレンツェです" ),
PhotoData( type:"景色", imageName:"CC0_07", title:"景色4", message:"ひまわりです" ),
PhotoData( type:"景色", imageName:"CC0_10", title:"景色5", message:"海に日が沈みます" ),
PhotoData( type:"食べ物", imageName:"CC0_05", title: "ハンバーガーセット", message: "おいしいです" ),
PhotoData( type:"食べ物", imageName:"CC0_08", title: "カフェラテ", message: "おちつきます" ),
PhotoData( type:"食べ物", imageName:"CC0_09", title: "ケーキ", message: "あまいです" ),
PhotoData( type:"食べ物", imageName:"CC0_12", title: "お酒", message: "酔います" )
]
var body: some View {
List {
Section( "景色写真" ) {
ForEach( photos.filter { $0.type == "景色" } ) { photo in
NavigationLink( destination:{
SceneryDetail( data:photo )
},
label: {
SceneryRow( data:photo )
})
}
}
Section( "食べ物写真" ) {
ForEach( photos.filter { $0.type == "食べ物" } ) { photo in
NavigationLink( destination:{
FoodAndDrinkDetail( data:photo )
},
label: {
FoodAndDrinkRow( data:photo )
})
}
}
}
.listStyle( .grouped )
.navigationTitle( "写真集" )
}
}
|
これで食べ物写真リストもタップすると詳細画面に遷移するようになります。また景色写真とは異なる見た目の画面になっていることがわかると思います。
結果3#
タップ前#
食べ物写真タップ後#
ここまでで, Navigationを使った画面遷移の作り方は一区切りとなります。
データを設計し,データの内容によって表示の仕方を変える, 画面を切り替える方法を紹介しました。特にデータと見た目を独立させる点がポイントです。
データの作り方や画面の使い方を工夫することで, 様々なAppの動作を作っていくことができます。ぜひご自身が美しいと感じるAppをデザインしてみてください。