見出し画像

【Xcode】超初心者のためのSwiftUIチュートリアル14

Apple公式のSwiftUIチュートリアルを、プログラミング超初心者向けに優しく解説するシリーズ第14回。今回から「Composing Complex Interfaces(複雑なインターフェースの作成)」に入ります(前回の記事はこちら)。

この章ではアプリのホーム画面を作っていきます。データベースに入っているそれぞれのランドマークが、Lakes、Mountains、Riversの3つのカテゴリーに分かれて水平方向にスクロール表示されるビューができあがります。

スクリーンショット 2020-04-21 13.33.31

Appleの公式チュートリアルはこちらを参照してください。日本語で閲覧したい場合は、自動翻訳機能のあるGoogleChromeなどのブラウザを使用するといいでしょう。

1.セクション1/新しくCategoryHome.swiftを作る

まずこれまでと同様、プロジェクトファイルをダウンロードしましょう。

スクリーンショット 2020-04-18 12.07.27

ダウンロードしたZipファイルを開き、下図を参考に「StartingPoint」フォルダの中のプロジェクトファイルを開きます。

スクリーンショット 2020-04-18 12.50.35

プロジェクト画面を開いたら、まずは新しいSwiftUIファイルを作成します。左上のFile>Mew>File...の順にクリックしましょう。

スクリーンショット 2020-04-18 12.57.30

下のような画面が開きます。SwiftUI Viewファイルを選択したら右下のNextをクリックしましょう。

スクリーンショット 2020-04-18 13.00.54

一番上のSave As:のところにファイル名をCategoryHome.swiftと入力します。次にGroup欄右側の青い部分をクリックして、下図の「Landmarks」フォルダを選択。終わったら右下のCreateをクリックしましょう。

スクリーンショット 2020-04-18 13.05.39

画面右側のファイル一覧を見ると、新しいswiftファイルができています。ドラッグで移動して、わかりやすくファイル位置を整理しておきましょう。これから作る画面はアプリのホーム画面になります。

スクリーンショット 2020-04-18 13.10.38

 CategoryHome.swiftファイルをクリックして中身を表示したら、文字列"Hello World"を、いったん"Landmarks Content"に書き換えましょう。

スクリーンショット 2020-04-18 13.15.50

これで新しいビューファイルができました。

2.SceneDelegate.swiftでホーム画面を変更する

現段階では、第6回で作成したLandmarkListがアプリのホーム画面になっているので、SceneDelegate.swiftのrootViewを書き換えてCategyHomeをホーム画面に設定します。

スクリーンショット 2020-04-19 21.27.29

これでアプリを起動したとき、最初にCategoryHome.swiftのビューをホーム画面として表示するようになりました。

このホーム画面に、すべての項目が表示されるように書き換えていきます。まずは先ほどの「Text("Landmarks Content")」をNavigationViewの中に入れ込みましょう。そしてナビゲーションバーのタイトルを「Featured(おすすめ)」にします。下図の通り.navigationBarTitle(Text("Featured"))を追記しましょう。

スクリーンショット 2020-04-19 21.52.35

画面はこのようになりました。


スクリーンショット 2020-04-19 21.57.44

4.セクション2/カテゴリーリストを作成する

今度は、Dictionary型を用いて各ランドマークをLakes、Rivers、Mountainsの3種類に分類します。「Dictionary型」についてはこのセクションの後に説明しますので、ここではとりあえずコードを書き進めましょう。

CategoryHome.swiftに赤い四角の中身を入力してください。

スクリーンショット 2020-04-20 0.02.48

//LandmarkData内の「category」をkeyにしてvalueをグループ化する
var categories: [String: [Landmark]] { 
       Dictionary(
           grouping: landmarkData,
           by: { $0.category.rawValue}
       )
   }


ランドマークの元データLandmarkData.jsonには、それぞれのランドマークの名前や位置、州などの要素が書かれています。その中の「category」という要素には、Lakes、Rivers、Mountainsのいずれかの値が入っています。その値を「key」にして、ランドマークを3つにグループ化するわけです。

スクリーンショット 2020-04-19 22.06.40

次にNavigationViewの中にカテゴリーリストを作ります。Listを使って上で抽出したcategoryの値(key)をテキストで表示します。

スクリーンショット 2020-04-26 12.25.59

var body: some View {
       NavigationView {
           List {
               ForEach(categories.keys.sorted(), id: \.self) { key in
                   Text(key) //keyとなる値をテキストとしてリストに入れる
               }
           }
           .navigationBarTitle("Featured")
       }
   }

プレビューするとこうなります。

スクリーンショット 2020-04-28 13.59.07

Dictionary型とは

key」と呼ばれる文字列などで「value」の値を取得するのがDictionary型です。...と言われても、初心者にはなんじゃそりゃ??という感じですね。
一通りコードを書いてフンワリと理解できた方もいるかもしれませんが、ここでlandmarkData.jsonを具体例としてDitionary型の使い方を説明します。
(jsonファイルを参照しながら読むとわかりやすいです)

このセクションでは「category」という項目の文字列を「key」にして、landmarkDataから「Turtle Rock(に属する名称、州、位置などの情報の集合体)」や「Silver Salmon Creek(に属する名称、州、位置などの情報の集合体)」に含まれている要素「value」を取得します。
例えばcategory「Rivers」というkeyによって取得するvalueは「Turtle Rock」や「Charley Rivers」などcategoryが「Rivers」になっているランドマークの要素です。
同様に「Mountains」というkeyで取得できるのは「Chilkoot Trail」や「Lake McDonald」などに属するvalueとなります。

なお、Lake McDonaldはランドマーク名に「Lake」が入っていますが、keyはMountainsなので、「Mountains」に分類されます。名前がどうあれ、分類はkeyであるcategoryが基準となるのです。

5.セクション3/CategoryRow.swiftでリストの各行を設定

ここからはLakes、Rivers、Mountainsのそれぞれのカテゴリーに属するランドマークを、1つの行に横並びに表示するための作業をします。

CategoryRow.swiftという名前の新しいビューファイルを作ります。手順は先ほどCategoryHome.swiftを作った時と同様です。
新しいビューファイルができたら、中身を下のように書き換えます。

スクリーンショット 2020-04-28 16.04.08

import SwiftUI

struct CategoryRow: View {
   
   var categoryName: String
   var items: [Landmark]
   
   var body: some View {
       Text(self.categoryName)
           .font(.headline)
   }
}

struct CategoryRow_Previews: PreviewProvider {
   static var previews: some View {
       CategoryRow(
           //LandmarkData[0]内の「category」項目を表示
           categoryName: landmarkData[0].category.rawValue,
           items: Array(landmarkData.prefix(3))
       )
   }
}

プレビューを表示する時は、表示する中身を具体的に指定する必要があります。ここでは「Turtle Rock」に関する要素が入っている配列[0]のcategory要素「Rivers」が表示されます。(※チュートリアルでは「Mountain」になっていますが、データに何らかの変更があったと思われます)

スクリーンショット 2020-04-28 17.54.30

試しにlandmarkData[0]の数値を変えると、対応する配列のcategory要素に表示が変わります。
例えば[1]にするとSilver Salmon Creekのcategory要素「Lakes」に、[5]にするとLake McDonaldのcategory要素「Mountains」になります。自分で数字を変えて、jsonファイルの中身と比較してみるとわかりやすいでしょう。

確認できたら今度はCategoryHome.swiftを開き、今作成したCategoryRowファイルで取得したcategoryの要素を、CategoryHomeの各行に表示する形に書き換えます。さっきとプレビューの表示は一緒ですが、こうすることで各行の中に多様なvalueを入れ込めるようになります。

スクリーンショット 2020-04-29 16.09.11

var body: some View {
    NavigationView {
        List {
            ForEach(categories.keys.sorted(), id: \.self) { key in
                CategoryRow(categoryName: key, items: self.categories[key]!)
            }
        }
        .navigationBarTitle("Featured")
    }
}


6.ForEachで各カテゴリーのランドマーク名を一覧表示

CategoryHomeファイルの書き換えが終わったら、再びCategoryRowに戻ります。
下記のように書き換え、HStackでそのカテゴリーのランドマークの名前が横並びに表示されるようにします(プレビュー画面設定はそのまま)。

スクリーンショット 2020-04-29 5.51.35

var body: some View {
    HStack(alignment: .top, spacing: 0) {
        ForEach(self.items) { landmark in
            Text(landmark.name)
                .font(.headline)
        }
    }
}

この状態でプレビューすると、LandmarkDataの配列のうち最初の3つからnameのvalueが抽出され、横並びに表示されます。

スクリーンショット 2020-04-29 6.03.12

表示されるnameの数はプレビュー画面設定の最後の行

items: Array(landmarkData.prefix(3))

で設定しています。prefix()の中の数値を変えると、表示されるnameの数が変化します。例えば5にすると、下のような表示になります。

スクリーンショット 2020-04-29 6.16.16

数が増えるごとに1つ当たりの横幅が狭くなり、表示が崩れてしまいますね。

7.複数のランドマーク名をスクロール表示させる

そこで、ランドマーク名が増えても横スクロールで表示できるビューにします。CategoryRowを下図のように書き換えてください。プレビュー設定は4つの要素が表示されるように変更します。

スクリーンショット 2020-04-29 6.34.51

import SwiftUI

struct CategoryRow: View {
   
   var categoryName: String
   var items: [Landmark]
   
   var body: some View {
       
       VStack(alignment: .leading) {
           //カテゴリー名
           Text(self.categoryName)
               .font(.headline)
               .padding(.leading, 15)
               .padding(.top, 5)
           
           //配列要素のスクロールビュー
           ScrollView(.horizontal, showsIndicators: false) {
               HStack(alignment: .top, spacing: 0) {
                   ForEach(self.items) { landmark in
                       Text(landmark.name)
                   }
               }
           }
           .frame(height: 185) //スクロールビューのフレームの高さ
       }
   }
}

struct CategoryRow_Previews: PreviewProvider {
   static var previews: some View {
       CategoryRow(
           //LandmarkData配列0内の「category」項目を表示
           categoryName: landmarkData[0].category.rawValue,
           //LandmarkData配列の最初の4つを表示
           items: Array(landmarkData.prefix(4))
       )
   }
}

これをライブプレビューで確認すると、このようになります。ランドマーク名が1行で連なり、画面に収まらない部分も横にスクロールしたら表示されます。

画像25

これで各行の横スクロールビューのベースができ上がりました。
現段階で、CategoryHomeのライブプレビューをみるとこんな感じです。

画像24


次回のセクション4からは、それぞれのカテゴリー行ごとにランドマーク名と画像を横に並べて表示して、タップすると詳細画面に遷移する動きを作っていきます。

関連記事は下のマガジンをご覧ください。


この記事が気に入ったら、サポートをしてみませんか?
気軽にクリエイターの支援と、記事のオススメができます!
*\(^o^)/*
13
40代にしてプログラミングの勉強を始めました。swiftやmicro:bitについてあれこれ書いていきます。

こちらでもピックアップされています

超初心者のためのSwiftUIチュートリアルまとめ
超初心者のためのSwiftUIチュートリアルまとめ
  • 17本

Apple公式のswiftUIチュートリアルを、プログラミングを始めたばかりの超初心者でもわかるように解説した記事のまとめ。

コメントを投稿するには、 ログイン または 会員登録 をする必要があります。