[SwiftUI]Listを詳しく知りたい我
何気なく使っているListを一度調べ直そうの会
以下を読む。
概要
1 つの列に配置されたデータ行を表示するコンテナー。
・シンプルなリスト例
var body: some View {
List {
Text("A List Item")
Text("A Second List Item")
Text("A Third List Item")
}
}
・動的にリスト例
より一般的には、基礎となるデータのコレクションからリストを動的に作成します。次の例は、Identifiable に準拠する Ocean 型の配列から単純なリストを作成する方法を示しています。
struct Ocean: Identifiable {
let name: String
let id = UUID()
}
private var oceans = [
Ocean(name: "Pacific"),
Ocean(name: "Atlantic"),
Ocean(name: "Indian"),
Ocean(name: "Southern"),
Ocean(name: "Arctic")
]
var body: some View {
List(oceans) {
Text($0.name)
}
}
・選択可能なリスト例
選択可能なListを生成するには、以下2つの条件が必要。
・引数(selection)に選択値を格納するプロパティを指定する。
・対象のViewを編集モードにする。
複数選択を可能にする場合は、編集ボタンをつける必要があるので注意。
タップまたはクリックで 1 つの選択を行うと、選択されたセルの外観が変わり、選択されていることを示します。タップ ジェスチャで複数の選択を有効にするには、editMode 値を変更するか、アプリのインターフェイスに EditButton を追加して、リストを編集モードにします。リストを編集モードにすると、リストの各リスト項目の横に円が表示されます。ユーザーが関連する項目を選択すると、円にチェックマークが表示されます。上記の例では、編集モード中にタイトルが [完了] に変わる [編集] ボタンを使用しています。
struct SearchView: View {
@State private var searchText: String = ""
@StateObject private var model: SearchModel = .init()
// Int部分は適宜変える。この型重要!
@State private var multiSelection = Set<Int>()
var body: some View {
NavigationStack {
// selectionの指定。ここでタップされた行がバインドされる。
List(model.repositories.items, selection: $multiSelection) {
SearchViewCell(
title: $0.name,
description: $0.description
)
}
.searchable(
text: $searchText,
prompt: "検索"
)
.onChange(of: searchText) { _, newValue in
model.searchRepository(query: newValue)
}
// 複数選択する場合は、編集ボタンが必須。
.toolbar { EditButton() }
}
}
}
以下も参考に!
・リフレッシュ例
標準の更新コントロールを使用してリストのコンテンツを更新可能にするには、refreshable(action:) 修飾子を使用します。次の例は、リストに標準の更新コントロールを追加する方法を示しています。ユーザーがリストの上部を下にドラッグすると、SwiftUI は更新コントロールを表示し、指定されたアクションを実行します。アクション クロージャ内で await 式を使用してデータを更新します。待機中の操作の間、更新インジケーターは表示されたままになります。
struct Ocean: Identifiable, Hashable {
let name: String
let id = UUID()
let stats: [String: String]
}
class OceanStore: ObservableObject {
@Published var oceans = [Ocean]()
func loadStats() async {}
}
@EnvironmentObject var store: OceanStore
var body: some View {
NavigationView {
List(store.oceans) { ocean in
HStack {
Text(ocean.name)
StatsSummary(stats: ocean.stats) // A custom view for showing statistics.
}
}
.refreshable {
await store.loadStats()
}
.navigationTitle("Oceans")
}
}
refreshableに
ついても調べてみる。
このビューを更新可能としてマークします。
nonisolated
func refreshable(action: @escaping () async -> Void) -> some View
ユーザーが更新を要求したときに SwiftUI が実行する非同期ハンドラー。このハンドラーを使用して、変更されたビューに表示されるモデル データの更新を開始します。ハンドラー内のすべての非同期呼び出しの前に await を使用します。
独自のビューにも更新機能を追加できます。その方法については、RefreshActionを参照してください。
・2次元リスト例
section毎にListを分けるのはいろんなところで使いそう。
struct ContentView: View {
struct Sea: Hashable, Identifiable {
let name: String
let id = UUID()
}
struct OceanRegion: Identifiable {
let name: String
let seas: [Sea]
let id = UUID()
}
private let oceanRegions: [OceanRegion] = [
OceanRegion(name: "Pacific",
seas: [Sea(name: "Australasian Mediterranean"),
Sea(name: "Philippine"),
Sea(name: "Coral"),
Sea(name: "South China")]),
OceanRegion(name: "Atlantic",
seas: [Sea(name: "American Mediterranean"),
Sea(name: "Sargasso"),
Sea(name: "Caribbean")]),
OceanRegion(name: "Indian",
seas: [Sea(name: "Bay of Bengal")]),
OceanRegion(name: "Southern",
seas: [Sea(name: "Weddell")]),
OceanRegion(name: "Arctic",
seas: [Sea(name: "Greenland")])
]
@State private var singleSelection: UUID?
var body: some View {
NavigationView {
List(selection: $singleSelection) {
ForEach(oceanRegions) { region in
Section(header: Text("Major \(region.name) Ocean Seas")) {
ForEach(region.seas) { sea in
Text(sea.name)
}
}
}
}
.navigationTitle("Oceans and Seas")
}
}
}