記事


リストでデータを表示する


プラットフォームに適した外観でデータのコレクションを視覚化します。



概観


多くのアプリで、データの集合を縦方向のリストに表示することが一般的です。連絡先リスト、イベントスケジュール、カテゴリー一覧、買い物リストなど、List は様々な場面で活用されます。


List (リスト) ビューは、アイテムのコレクションを縦に表示し、必要に応じて行を読み込み、行が画面に収まらない場合はスクロール機能を追加するため、大規模なデータコレクションの表示に適しています。


デフォルトでは、リストビューはプラットフォームに適したスタイルを要素にも適用します。例えば、iOS では、リストのデフォルト構成では、各行の間に区切り線が表示され、ナビゲーションアクションを開始するアイテムの横に展開インジケーターが追加されます。


注意
プラットフォームに適したスタイル(行区切りや自動開示インジケータなど)をリストから削除したい場合は、代わりに LazyVStack の使用を検討してください。lazy (遅延) スタックの操作方法の詳細については、パフォーマンスの高いスクロール可能なスタックの作成 をご覧ください。

この記事におけるコードは、リストビューを使用して会社のスタッフディレクトリを表示する方法を示しています。各セクションでは、カスタムセルの追加、リストのセクション分割、リストの選択による詳細ビューへの移動などにより、リストの利便性が向上しています。



反復処理のためにデータを準備


List の最も一般的な用途は、データモデル内の情報のコレクションを表すことです。以下の例では、namephoneNumber のプロパティを持つ Identifiable 型として Person を定義しています。staff という配列には、この型のインスタンスが 2 つ含まれています。


struct Person: Identifiable {
     let id = UUID()
     var name: String
     var phoneNumber: String
 }

var staff = [
    Person(name: "Juan Chavez", phoneNumber: "(408) 555-4301"),
    Person(name: "Mei Chen", phoneNumber: "(919) 555-2481")
]

配列の内容をリストとして表示するために、この例では List インスタンスを作成します。リストのコンテンツビルダーは、ForEach を使用して staff 配列を反復処理します。配列の各メンバーについて、リストは Person の名前を含む新しい Text をインスタンス化し、行ビューを作成します。


struct StaffList: View {
    var body: some View {
        List {
            ForEach(staff) { person in
                Text(person.name)
            }
        }
    }
}


リストのメンバーは互いに一意に識別可能でなければなりません。一意の ID (識別子) を使用することで、SwiftUI は挿入、削除、移動といった基になるデータの変更に対してアニメーションを自動的に生成できます。リストのメンバーを識別するには、Person のように Identifiable に準拠した型を使用するか、その型の一意のプロパティへのキーパスを id パラメータに提供することで識別します。上記のリストにデータを入力する ForEach は、この動作に依存しており、メンバーの RandomAccessCollection を反復処理に受け取る List イニシャライザも同様です。


重要
Identifiable データに使用する値は一意でなければなりません。UUID またはデータベースの行識別子の使用はどちらも良い選択ですが、個人名や電話番号などのデータを使用すると重複が発生する可能性があります。

行内にデータを表示する


List 内の各行は SwiftUI の View でなければなりません。Image ビューや Text ビューなどの単一のビューでデータを表現できる場合もあれば、複数のビューを組み合わせてより複雑なものを表現するカスタムビューを定義する必要がある場合もあります。


行ビューがより洗練されていくにつれて、ビューを個別のビュー構造にリファクタリングし、行のレンダリングに必要なデータを渡せるようにします。以下の例では、PersonRowView を定義して、Person の 2 行ビューを作成します。フォント、色、システムの "電話" アイコン画像を使用して、データの視覚的なスタイルを設定します。


struct PersonRowView: View {
    var person: Person

    var body: some View {
        VStack(alignment: .leading, spacing: 3) {
            Text(person.name)
                .foregroundColor(.primary)
                .font(.headline)
            HStack(spacing: 3) {
                Label(person.phoneNumber, systemImage: "phone")
            }
            .foregroundColor(.secondary)
            .font(.subheadline)
        }
    }
}

struct StaffList: View {
    var body: some View {
        List {
            ForEach(staff) { person in
                PersonRowView(person: person)
            }
        }
    }
}


リスト行内でよく使用されるビューの種類を構成する方法の詳細については、スタック ビューを使用したレイアウトのビルド を参照してください。



セクションでデータ階層を表現


List ビューでは、階層のレベルでデータを表示し、関連するデータをセクションにグループ化することもできます。


複数の部門を含む会社全体を表す拡張データモデルを考えてみましょう。各 Department には namePerson インスタンスの配列があり、会社には Department 型の配列があります。


struct Department: Identifiable {
    let id = UUID()
    var name: String
    var staff: [Person]
}

struct Company {
    var departments: [Department]
}

var company = Company(departments: [
    Department(name: "Sales", staff: [
        Person(name: "Juan Chavez", phoneNumber: "(408) 555-4301"),
        Person(name: "Mei Chen", phoneNumber: "(919) 555-2481"),
        // ...
    ]),
    Department(name: "Engineering", staff: [
        Person(name: "Bill James", phoneNumber: "(408) 555-4450"),
        Person(name: "Anne Johnson", phoneNumber: "(417) 555-9311"),
        // ...
    ]),
    // ...
])

Section ビューを使用して、List 内のデータに階層構造を与えます。まず List を作成し、ForEach を使用して company.departments 配列を反復処理し、各部門の Section ビューを作成します。セクションのビュービルダー内で、ForEach を使用して部門の staff を反復処理し、各 Person ごとにカスタマイズされたビューを返します。


List {
     ForEach(company.departments) { department in
         Section(header: Text(department.name)) {
             ForEach(department.staff) { person in
                PersonRowView(person: person)
             }
         }
     }
 }


注意
あなたのデータ階層が深すぎて、単一レベルのセクションと行で表現できない場合は、OutlineGroupDisclosureGroup が適している可能性があります。これらのビューは、開示メタファーを使用して、ユーザーが階層内の任意の深さまで貫いて行けるようにします。


ナビゲーションにリストを使用する


NavigationView   廃止   に含まれる List 内で NavigationLink を使用すると、プラットフォームに適したビジュアルスタイルが追加され、場合によってはナビゲーションの構造を提供する追加のコンテナビューも追加されます。SwiftUI は、実行環境に基づいて、以下の 2 つのビジュアル表現のいずれかを使用します。


  • 開示インジケーター付きのリスト。ユーザーがリスト項目を選択すると、アニメーション化されたナビゲーションで目的のシーンに移動します。SwiftUI は、以下で説明する場合を除き、watchOS、tvOS、およびほとんどの iOS デバイスでこの表示を使用します。

  • 2 つのパネルで分割したビュー。トップレベルのデータは左側にリストとして表示され、詳細データは右側に表示されます。この表示を実現するには、リストの後にプレースホルダービューも影響する必要があります。このプレースホルダーは、ユーザーが選択するまで詳細ペインに表示されます。SwiftUI は、horizontalSizeClass 環境値で示される十分な水平方向のスペースがある macOS、iPadOS、および iOS デバイスで、この 2 パネルアプローチを使用します。

  • 以下の例では、リストをナビゲーションビューで包み込むことで、ナビゲーションベースの UI を設定しています。NavigationLink のインスタンスはリストの行を包み込み、ユーザーが行をタップした際にナビゲートする destination ビューを提供します。プラットフォームで分割ビューナビゲーションが適切な場合、右側のパネルには初期状態で "選択されていない" のプレースホルダービューが表示されます。ユーザーが選択を行うと、ナビゲーションビューによってこのプレースホルダービューが移動先のビューに置き換えられます。


    NavigationView {
        List {
            ForEach(company.departments) { department in
                Section(header: Text(department.name)) {
                    ForEach(department.staff) { person in
                        NavigationLink(destination: PersonDetailView(person: person)) {
                            PersonRowView(person: person)
                        }
                    }
                }
            }
        }
        .navigationTitle("Staff Directory")
    
        // Placeholder
        Text("No Selection")
            .font(.headline)
    }
    

    この例では、destination (宛先) として渡されるビューは PersonDetailView で、リストからの情報を繰り返し表示します。より複雑なアプリでは、この詳細ビューに、リストの行に収まりきらないほど多くの Person 情報が表示される可能性があります。


    struct PersonDetailView: View {
        var person: Person
    
        var body: some View {
            VStack {
                Text(person.name)
                    .foregroundColor(.primary)
                    .font(.title)
                    .padding()
                HStack {
                    Label(person.phoneNumber, systemImage: "phone")
                }
                .foregroundColor(.secondary)
            }
        }
    }
    

    ほとんどの iOS デバイス(コンパクトな水平サイズクラスを持つデバイス)では、リストは独自のビューとして表示され、行をタップするとアニメーション付きの遷移で目的のビューに移行します。以下の図は、ユーザーが選択を行った際に表示されるリストビューと、目的のビューの両方を示しています。



    一方、iPadOS と macOS では、リストと詳細ビューが複数列のビューとして一緒に表示されます。以下の図は、選択を行う前の macOS での表示を示しています。つまり、"選択なし" のプレースホルダービューが詳細列にまだ表示されています。



    navigationViewStyle(_:)   廃止   ビュー修飾子を使用すると、NavigationView のデフォルトの動作を変更できます。例えば iOS では、StackNavigationViewStyle   廃止   を指定すると、iPad の横向き表示でも 1 列モードが強制されます。





    以下も見よ


    リストの作成


    struct List

    1 つの列に配置されたデータ行を表示するコンテナー。オプションで 1 つ以上のメンバーを選択することもできます。


    func listStyle<S>(S) -> some View

    このビュー内のリストのスタイルを設定します。














    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ












    トップへ