SwiftUI异步加载List时出现动画闪烁重复渲染Bug如何解决?
问题根因
该闪烁问题由状态更新时序错误导致:你在搜索关键词变化时先立即切换searchByWordView = false进入搜索结果展示状态,再异步请求新的搜索结果。在异步请求的间隙,List会先渲染FoodList中存储的上一次搜索旧数据,等新请求结果返回后才会刷新为新内容,因此出现了旧列表短暂闪现的问题。
修复步骤
1. 新增状态变量
在ContentView中新增两个状态变量,用于控制搜索流程和取消无效请求:
@State private var isSearching: Bool = false @State private var currentSearchTask: Task<Void, Never>?
2. 调整搜索触发逻辑
修改selectedFood的onChange回调,调整状态更新顺序,等搜索结果返回后再切换到搜索结果展示状态:
.onChange(of: selectedFood, perform: { keyword in // 取消上一次未完成的搜索请求 currentSearchTask?.cancel() if keyword.isEmpty { searchByWordView = true FoodList.removeAll() isSearching = false return } isSearching = true currentSearchTask = Task { // 可选:添加300ms防抖,减少输入过程中的请求次数 try? await Task.sleep(nanoseconds: 300_000_000) guard !Task.isCancelled, selectedFood == keyword else { return } let newSearchResult = await GetFoodItemsByName(_name: keyword) guard !Task.isCancelled, selectedFood == keyword else { return } FoodList = newSearchResult searchByWordView = false isSearching = false } })
3. 优化列表展示逻辑
给列表添加搜索中状态的展示,避免请求过程中出现空白或者旧内容:
List { if isSearching { Section { HStack(spacing: 8) { Spacer() ProgressView() Text("搜索中...") Spacer() } .padding(.vertical, 12) } } else if !searchByWordView { Section { ForEach(FoodList, id:\.self){ item in Button(action: { selectedFoodTemp = item.name addScreen.toggle() }){ Text(item.name) } .foregroundColor(.black) } } } else { Section { ForEach(FoodCList, id:\.self){ category in NavigationLink(destination: GetFoodCategoryItemsView(category: category.name)) { Text(category.name) } .foregroundColor(.black) } } } }
修改完成后即可解决列表闪烁的问题,同时还优化了快速输入时的请求性能,避免无效请求浪费资源。
内容的提问来源于stack exchange,提问作者Isaac
相关产品推荐
相关产品推荐

