SwiftUI列表滚动时行内@State状态丢失问题求助
问题原因
- List视图的复用机制:SwiftUI的List本质是基于可复用单元实现的滚动列表,当某一行完全滚动出屏幕可视区域后,对应的行视图实例会被系统回收销毁,后续该行再次滑入屏幕时会重新初始化一个全新的行视图实例。
- @State的生命周期限制:
@State是SwiftUI专为视图内部私有状态设计的属性包装器,它的存储完全绑定在对应的视图实例上,视图实例销毁时@State存储的所有数据也会同步释放。你当前把计数count定义为TestViewRow的内部@State,每次行视图重建时count都会被重置为初始值0,就出现了滚动后计数丢失的问题。
解决方案
推荐将行级状态和父层数据源绑定,利用父视图生命周期更长的特性持久化存储计数,修改后的代码如下:
- 首先定义承载条目内容和计数的数据源结构
struct ListItem: Identifiable { let id = UUID() let content: String var count: Int = 0 }
- 修改父视图,用绑定将数据源传递给子行视图
struct TestView : View { @State private var listItems:[ListItem] = (0..<50).map { ListItem(content: String($0)) } var body: some View { List($listItems) { $item in TestViewRow(item: $item) } } }
- 修改子行视图,用@Binding接收状态,不再维护私有@State
struct TestViewRow: View { @Binding var item: ListItem var body: some View { HStack { Button(item.content, action: { item.count += 1 }) Text(String(item.count)) Spacer() } } }
这种方案下计数存储在父视图的@State数据源中,不会因为子行视图的复用销毁丢失,滚动后状态可以正常保留。
内容的提问来源于stack exchange,提问作者James Crowley
相关产品推荐
相关产品推荐

