こんにちは。ymurao2です!
ScrollView
+ LazyVStack
で縦に長い画面を実装しているとき、VStack
とLazyVStack
の使い分けについて悩むことが少なからずあったので、調査しました
動作環境
Xcode15.0.1
調査コード
ScrollView {
+ // ここと
LazyVStack {
+ // ここと
LazyVStack {
ForEach(0..<25, id: \.self) { i in
Text(String(i))
.padding()
.onAppear {
print("upper:" + String(i))
}
}
}
.background(Color.gray)
+ // ここと
LazyVStack {
ForEach(25..<50, id: \.self) { i in
Text(String(i))
.padding()
.onAppear {
print("middle:" + String(i))
}
}
}
.background(Color.red)
+ // ここをいじります
LazyVStack {
ForEach(50..<75, id: \.self) { i in
Text(String(i))
.padding()
.onAppear {
print("lower:" + String(i))
}
}
}
.background(Color.blue)
}
}
1.LavyVStack
+ LazyVStack
ScrollView {
LazyVStack {
LazyVStack {
// 省略
}
.background(Color.gray)
LazyVStack {
// 省略
}
.background(Color.red)
LazyVStack {
// 省略
}
.background(Color.blue)
}
}
View
が表示される前にonAppear
は発火しているので、ログは実際に表示されるタイミングより早く表示されています
Stack Overflow参照
このパターンの場合、全てのViewが遅延読み込みされていました
2.LazyVStack
+ VStack
// 最初のコードとのdiff
ScrollView {
LazyVStack {
+ VStack {
// 省略
}
.background(Color.gray)
+ VStack {
// 省略
}
.background(Color.red)
+ VStack {
// 省略
}
.background(Color.blue)
}
}
このパターンの場合、VStack
の先頭がレンダリングされるときに、VStack
の内のonAppear
が全て発火していました
3.VStack
+ LazyVStack
// 最初のコードとのdiff
ScrollView {
+ VStack {
LazyVStack {
// 省略
}
.background(Color.gray)
LazyVStack {
// 省略
}
.background(Color.red)
LazyVStack {
// 省略
}
.background(Color.blue)
}
}
1.のLavyVStack + LazyVStack
と同じ結果になりました
このパターンも良さそうに見えましたが、別の問題がありました
// 最初のコードとのdiff
ScrollView {
VStack {
LazyVStack {
// 省略
}
.background(Color.gray)
LazyVStack {
// 省略
}
.background(Color.red)
LazyVStack {
// 省略
}
.background(Color.blue)
+ Text("表示されたぞ!!!")
+ .onAppear {
+ print("表示されたぞ!!!")
+ }
}
}
一番下にText
を差し込んだところ、こちらは表示される前にonAppear
が発火しました
これは期待通りの動作とは言えなさそうです
4.VStack
+ VStack
// 最初のコードとのdiff
ScrollView {
+ VStack {
+ VStack {
// 省略
}
.background(Color.gray)
+ VStack {
// 省略
}
.background(Color.red)
+ VStack {
// 省略
}
.background(Color.blue)
}
}
Gifだと分かりにくいですが、全てのView
のonAppear
が一度に発火していました
まとめ
実装方法 | 結果 | 評価 |
---|---|---|
LavyVStack + LazyVStack
|
全てのView が遅延読み込みされた |
◎ |
LazyVStack + VStack
|
VStack 内のView のonAppear が同時に発火 |
× |
LazyVStack + VStack
|
VStack 内の要素が全てVStack に入っていれば問題なさそう |
△ |
VStack + VStack
|
全てのView が遅延読み込みされない |
× |
調査の結果、LazyVStack
+ LazyVStack
で実装するのが良さそうに見えました
この記事がお役に立てば、ぜひいいね👍お願いします!
参考文献
LazyVStackを使用すると描画処理が何度も走ってしまう
lazyvstack-row-onappear-is-called-early