ForEachを使った一覧表示
2021年03月09日
複数の要素を一覧表示したい場合、SwiftUIでは ForEach
を使用します
struct ContentView: View {
var texts = ["a", "b", "c", "d", "e"]
var body: some View {
VStack {
ForEach(texts, id: \.self, content: { t in
Text(t)
})
}
}
}
クロージャの最後の関数を外に出す機能を使用して書かれる事が多いため、以下のように記述される事が多いです
struct ContentView: View {
var texts = ["a", "b", "c", "d", "e"]
var body: some View {
VStack {
ForEach(texts, id: \.self) { t in
Text(t)
}
}
}
}
↑ では VStack
でラップしているため縦並びになっていますが、 HStack
を使えば横並びになります。
struct ContentView: View {
var texts = ["a", "b", "c", "d", "e"]
var body: some View {
HStack {
ForEach(texts, id: \.self) { t in
Text(t)
}
}
}
}
idについて
idにはForEachでループさせる値を一意に識別出来るプロパティを*** KeyPath
を用いて指定***します。
そしてForEachでループさせる値に 追加、更新、削除 を行った場合に id を用いて再描画がされます。
例えば以下のような User
というオブジェクトを作った場合 id
には以下のように指定が出来ます。
struct User {
var name: String
var age: Int
}
struct ContentView: View {
var users = [User(name: "Hanako", age: 20), User(name: "Taro", age: 30)]
var body: some View {
VStack {
ForEach(users, id: \User.name) { user in
Text("\(user.name) is \(user.age)")
}
}
}
}
\User.name
の部分は省略系を使って \.name
と記載する事がほとんどです。
ForEach(users, id: \.name) { user in
Text("\(user.name) is \(user.age)")
}
また上記の例では \.name
を使用しましたが、もちろん \.age
を使用する事も出来ます。
ForEach(users, id: \.age) { user in
Text("\(user.name) is \(user.age)")
}
ただし実際のプロジェクトの場合、name
もage
も一意であるかを判定しづらいケースがほとんどと思われるため、
どちらもいい例ではありません。
Identifiable
に準拠させるのが望ましいでしょう。
Identifiableを使う
Identifiable
に準拠すると id
というプロパティを持つ事が必須になります。
public protocol Identifiable {
/// A type representing the stable identity of the entity associated with `self`.
associatedtype ID : Hashable
/// The stable identity of the entity associated with `self`.
var id: Self.ID { get }
}
User
に対して Identifiable
を準拠させると以下のように書けます
struct User: Identifiable {
var id = UUID()
var name: String
var age: Int
}
struct ContentView: View {
var users = [User(name: "Hanako", age: 20), User(name: "Taro", age: 30)]
var body: some View {
VStack {
ForEach(users, id: \.id) { user in
Text("\(user.name) is \(user.age)")
}
}
}
}
更にForEach
でループさせる値が Identifiable
に準拠している場合、
id:
を省略して書けるため以下のように書けます
struct User: Identifiable {
var id = UUID()
var name: String
var age: Int
}
struct ContentView: View {
var users = [User(name: "Hanako", age: 20), User(name: "Taro", age: 30)]
var body: some View {
VStack {
ForEach(users) { user in
Text("\(user.name) is \(user.age)")
}
}
}
}