前回リスト用のデータを追加しましたが、表示の切り替えやセクションわけができませんでした。今回はデータに種別を追加して、表示の出しわけをしてみようと思います。

  • 前回のコードに続けて書く
  • PhotoDataに変数 type を増やす
    • typeは「データの種類」

まず、データの種類がわかるようにPhotoDataを改良します。追加位置は自由ですが、下記の例ではidとimageNameの間に入れています。

コード1

1
2
3
4
5
6
7
8
9
import Foundation

struct PhotoData : Identifiable {
    var id = UUID()
    var type:String
    var imageName:String
    var title:String
    var message:String
}

PhotoDataの構造を変えたので、ContentViewでPhotoDataを使う時typeの値を求められます。 それぞれのPhotoDataがどんな種類のデータであるか、typeに入力していきます。

  • ContentViewのphotos:[PhotoData]の各情報にtypeを追加する
    • 景色のデータは type:”景色” と書く
    • 食べ物のデータは type:”食べ物” と書く

コード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
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 ) { photo in
                    SceneryRow( data:photo )
                }
            }
        }
        .listStyle( .grouped )
    }
}

この段階では表示に変化はありません。

結果1

swiftui_2_4_2_1.png

配列.filterでの絞り込み

では、このデータのtypeを用いて表示を工夫したいと思います。 データのtypeが"景色"であるものに絞り込みます。配列の.filter を用いることで条件に合わせてデータを絞れます。

  • ContentViewのForEachで用いる配列を書き換える
  • photos.filter { $0.type == “景色” } と書く
    • type = ”景色”のデータのみの配列 が得られる

コード3

 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
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 )
                }
            }
        }
        .listStyle( .grouped )
    }
}

結果2

swiftui_2_4_3_1.png


次にfilterで表示されなくなった食べ物データを表示したいと思います。しかし景色とは別の表示にしたいので、 FoodAndDrinkRow を使います。FoodAndDrinkRowでPhotoDataを受け取れるように改造します。

  • FoodAndDrinkRowの受け取る値を, data:PhotoData に変更

    • 受け取る値にしていたimageName, title, messageは削除する
  • 値の使用部分をPhotoDataの値を使うように変更する

    • imageName -> data.imageName
    • title -> data.title
    • message -> data.message

コード4

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import SwiftUI

struct FoodAndDrinkRow : View {
    var data:PhotoData
    
    var body: some View {
        VStack( alignment:.leading ) {
            Image( data.imageName )
            .resizable()
            .scaledToFit()
            .frame( maxHeight:200 )
            
            Text( data.title )
            .font( .system( size:20.0 ) )
            .padding( .bottom, 10 )
            
            Text( data.message )
            .font( .system( size:14.0 ) )
            .foregroundStyle( .secondary )
        }
        .padding( .vertical, 10.0 )
    }
}

さて、ここまでで準備が整いました。 ContentViewのListに食べ物セクションを追加し、typeが"食べ物"になっているものに絞ってリストに使ってみましょう。

  • ContentViewのListに食べ物Sectionを追加
    • ForEachでFoodAndDrinkRowを繰り返し作る
    • photos.filter { $0.type == “食べ物” } でデータを絞る

コード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
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 )
    }
}

食べ物が異なる表示でリスト化されました。

同じデータ配列にまとめていても、filter をうまく使うことでデータを使い分けることができました。

結果3

swiftui_2_4_3_2.png