鴻蒙HarmonyOS開發(fā)ArkUI中的LazyForEach和SwiftUI中的ForEach的區(qū)別
SwiftUI 提供了三種不同的機(jī)制來構(gòu)建一棵樹的動(dòng)態(tài)部分,F(xiàn)orEach就是其中之一。
ArkUI是鴻蒙的核心UI布局框架,除了ForEach,它還提供了LazyForEach,便于高性能開發(fā)。

由于ForEach往往和List搭配使用,我們會(huì)關(guān)注ForEach里的view是不是懶加載的,在SwiftUI中,只有ForEach,沒有公開資料描述ForEach加載方式,在WWDC20-10031的材料中提到過:List里的內(nèi)容總是以懶加載方式存在的。
然而測試發(fā)現(xiàn),當(dāng)list里的數(shù)據(jù)到達(dá)100000條后,初始化CPU占有率會(huì)達(dá)到100%,此時(shí)頁面雖然顯示了,但是無法滑動(dòng),即無響應(yīng)狀態(tài)。
List {
ForEach(0..<100000){ I in
ChatView(id: i)
}
}
why is the swiftUI list not lazy (compared to lazyVStack)?
Bad performance of large SwiftUI lists on macOS
一種優(yōu)化方式是給 List 里的內(nèi)容加上固定高度,這樣使用ForEach時(shí)SwiftUI就不需要計(jì)算每一個(gè)內(nèi)容的高度了。
List {
ForEach(0..<100000){ I in
ChatView(id: i)
.frame(width: 500, height: 15, alignment: .leading)
}
}
此外,SwiftUI提供了LazyVStack和LazyHStack這兩個(gè)容器,放在這兩個(gè)容器中的內(nèi)容是懶加載的。
相比SwiftUI,ArkUI中的LazyForEach無法實(shí)現(xiàn)以下場景:
1、SwiftUI中,可以使用ForEach直接遍歷,可以通過$0獲取索引。
VStack() {
// 遍歷從1-10,并創(chuàng)建從1-10的文本組件
ForEach((1...10), id: \.self) {
Text("\($0)…")
}
}
2、可以直接對(duì)數(shù)組進(jìn)行forEach,進(jìn)行遍歷:
let name = ["a","b","c","d"]
name.forEach {
switch $0 {
// 對(duì)name進(jìn)行遍歷,找到a
case let x where x.hasPrefix("a"):
print("\(x) is here")
default:
print("hi, \($0)")
}
}
SwiftUI和ArkUI中的LazyForEach使用差異如下:
1、自由控制遍歷的次數(shù)
在SwiftUI中,比如用數(shù)組的前一半數(shù)據(jù)繪制Text:
ForEach(0..<foo.count/2) { index in
Text(foo[index])
}
在ArkUI中,以下代碼報(bào)錯(cuò):Argument of type ‘boolean’ is not assignable to parameter of type ‘a(chǎn)ny[]’.
ForEach(0..<foo.count/2,
(item, index) => {
ListItem() {
Stack50View()
}
},
(item) => item.toString()
)
2、List和ForEach搭配使用靈活性
在SwiftUI中,List中可以提供多個(gè)數(shù)據(jù)源和ForEach組合,比如在List中添加一組ForEach,添加一個(gè)Text后再添加一組ForEach:
List{
ForEach(items,id:\.self){ item in
Text(item)
}
Text("其他內(nèi)容")
ForEach(0..<10){ I in
Text("id:\(i)")
}
}
在ArkUI中,List中只能添加ListItem,以下代碼報(bào)錯(cuò):The ‘List’ component can have only the ListItem, Section and ListItemGroup child component.
List() {
Text()
ForEach(this.arr,
(item, index) => {
ListItem() {
Stack50View()
}
},
(item) => item.toString()
)
ForEach(this.arr,
(item, index) => {
ListItem() {
Stack50View()
}
},
(item) => item.toString()
)
}
其他
SwiftUI中 ForEach內(nèi)對(duì)數(shù)據(jù)增、刪、改、查不需要通知框架層。
ArkUI中的LazyForEach需要告知框架層。