見出し画像

SwiftUI Tutorials - Composing Complex Interfaces

上部にランドマークを強調表示しながら、下部の方ではカテゴリー分けして表示できるようにします。

新しいSwiftUIファイルCategoryHome.swiftを作り構造体CategoryHome.を作ります。

  var body: some View {
       NavigationView {
           Text("Hello, World!")
              .navigationTitle("Featured")
       }
   }

NavigationViewを設置しタイトルを表示させます。


Create a Category List

landmarkData.json のファイルにはすでにカテゴリが記入されているので、

Landmark.swiftにプロパティを追加します。

 var category: Category
   enum Category: String, CaseIterable, Codable {
       case lakes = "Lakes"
       case rivers = "Rivers"
       case mountains = "Mountains"

次にModelData.swiftのクラスModelDataを編集していきます。

@Published var landmarks: [Landmark] = load("landmarkData.json")

としてすでに定義されているので 変数categoriesは変数landmarksを読み込んで使います。

  var categories: [String: [Landmark]] {
       Dictionary(
           grouping: landmarks,
           by: { $0.category.rawValue }
       )
   }

landmarksのデータを変数categoryで定義したenum Categoryの要素である3つのcaseのデータでカテゴリー分けをします。

grouping: landmarks,
by: { $0.category.rawValue }

次に、CategoryHome.swiftを編集していきます。

modelData を@EnvironmentObjectとして読み込みます。これで他のデータのアクセスができるようになります。

@EnvironmentObject var modelData: ModelData

そして

NavigationView {
           List {
               ForEach(modelData.categories.keys.sorted(), id: \.self) { key in
                   Text(key)
               }
           }
           .navigationTitle("Featured")
       }

でリスト表示させます。


Create a Category Row

カテゴリーは水平方向のスクロールビューを設定していきます。

新しいファイルCategoryRow.swiftを作り構造体CategoryRowを定義します。

変数を定義します。こちらがテンプレートになります。

 var categoryName: String
   var items: [Landmark]

Viewの部分を作ります。

var body: some View {
       VStack(alignment: .leading) {
           Text(categoryName)
               .font(.headline)
               .padding(.leading, 15)
               .padding(.top, 5)
           ScrollView(.horizontal, showsIndicators: false) {
               HStack(alignment: .top, spacing: 0) {
                   ForEach(items) { landmark in
                       Text(landmark.name)
                   }
               }
           }
           .frame(height: 185)
       }
   }

次に新しいCategoryItem.swiftファイルを作り、構造体 CategoryItemを作ります。こちらで実際のデータを入れるものを作ります。

  var landmark: Landmark

   var body: some View {
       VStack(alignment: .leading) {
           landmark.image
               .resizable()
               .frame(width: 155, height: 155)
               .cornerRadius(5)
           Text(landmark.name)
               .font(.caption)
       }
       .padding(.leading, 15)
   }

これをCategoryRow.swiftのScrollView()に適応します。

ScrollView(.horizontal, showsIndicators: false) {
               HStack(alignment: .top, spacing: 0) {
                   ForEach(items) { landmark in
                       CategoryItem(landmark: landmark)
                   }
               }
ForEach(items) { landmark in
 CategoryItem(landmark: landmark)
}


Complete the Category View

カテゴリーViewの仕上げをしていきます。

CategoryHome.swiftを編集していきます。CategoryRow()を入れ込んでいきます。

 List {
               ForEach(modelData.categories.keys.sorted(), id: \.self) { key in
                   CategoryRow(categoryName: key, items: modelData.categories[key]!)
               }
           }
CategoryRow(categoryName: key, items: modelData.categories[key]!)

Landmark.swiftの構造体Landmarkにプロパティを追加します。

 var isFeatured: Bool

そしてModelData.swiftのクラスModelDataに追加します。

    var features: [Landmark] {
       landmarks.filter { $0.isFeatured }
   }

再度CategoryHome.swiftの構造体CategoryHomeを編集します。

  NavigationView {
           List {
               modelData.features[0].image
                   .resizable()
                   .scaledToFill()
                   .frame(height: 200)
                   .clipped()
                   .listRowInsets(EdgeInsets())
                   
               ForEach(modelData.categories.keys.sorted(), id: \.self) { key in
                   CategoryRow(categoryName: key, items: modelData.categories[key]!)
               }
               
               .listRowInsets(EdgeInsets())
           }
           .navigationTitle("Featured")
       }
modelData.features[0].image

リストの一番上に注目のものを表示します。

.listRowInsets(EdgeInsets())
.listRowInsets(EdgeInsets())

そして、幅いっぱいに表示できるようにします。


Add Navigation Between Sections

カテゴリ分けされたデータにアクセスする方法を整理していきます。

CategoryRow.swiftから編集していきます。

 ScrollView(.horizontal, showsIndicators: false) {
               HStack(alignment: .top, spacing: 0) {
                   ForEach(items) { landmark in
                       NavigationLink(destination: LandmarkDetail(landmark: landmark)) {
                           CategoryItem(landmark: landmark)
                       }
                   }
               }
           }
NavigationLink(destination: LandmarkDetail(landmark: landmark)) {
CategoryItem(landmark: landmark)
}

詳細画面LandmarkDetailへのリンクをNavigationLinkを使って遷移させます。

次にCategoryItem.swiftを編集します。

VStack(alignment: .leading) {
           landmark.image
               .renderingMode(.original)
               .resizable()
               .frame(width: 155, height: 155)
               .cornerRadius(5)
           Text(landmark.name)
               .foregroundColor(.primary)
               .font(.caption)
       }

以下を追加しています。見た目の変更です。

.renderingMode(.original)
.foregroundColor(.primary)

最後にContentView.swiftを編集します。

タブで画面をTabView()を使って管 理するようにします。

struct ContentView: View {

   @State private var selection: Tab = .featured
   
   enum Tab {
       case featured
       case list
   }
   var body: some View {
       TabView(selection: $selection) {
           CategoryHome()
               .tabItem {
                   Label("Featured", systemImage: "star")
               }
               .tag(Tab.featured)
           LandmarkList()
               .tabItem {
                   Label("List", systemImage: "list.bullet")
               }
               .tag(Tab.list)
       }
   }
}


この記事が気に入ったらサポートをしてみませんか?