SwiftUI多列表Sheet快速Dismiss/Present异常问题求助
SwiftUI Sheet弹窗异常问题分析与疑问
场景与问题
正在构建类似Netflix iOS应用首页的多行单元格视图,结构如下:
CollectionView():展示单个项目(以矩形形式呈现)ListView():包含水平滚动的CollectionView项目列表ContentView():通过多个ListView实例构建垂直多行布局- 点击每个单元格时,通过
.sheet(isPresented:Content:)弹出对应详情视图
遇到的异常:快速点击第一个Collection的单元格弹出详情,下拉关闭后立即点击第二个Collection的项目,详情视图无法弹出;持续点击不同项目后,某一个详情视图弹出,关闭后之前所有尝试点击的详情会依次弹出。该问题偶尔在非快速点击场景下也会出现。
初始调试代码
CollectionModel 定义
struct CollectionModel: Identifiable { let id: UUID = UUID() let randomNumb: Int = Int.random(in: 1...10) static var mockArray: [CollectionModel] { [ CollectionModel(), CollectionModel(), CollectionModel(), CollectionModel(), CollectionModel(), CollectionModel(), CollectionModel(), CollectionModel(), CollectionModel(), CollectionModel() ] } }
主视图 ContentView
struct ContentView: View { var body: some View { ScrollView(.vertical, showsIndicators: false) { LazyVStack { ListView() ListView() ListView() ListView() } }.padding(.horizontal, 2) } }
水平列表视图 ListView
struct ListView: View { var listOfCollectionModel: [CollectionModel] = CollectionModel.mockArray var body: some View { ScrollView(.horizontal, showsIndicators: false) { LazyHStack{ ForEach(listOfCollectionModel) { model in CollectionView(collectionModel: model) } }.padding(.horizontal) } } }
单个项目视图 CollectionView
struct CollectionView: View { @State var collectionModel: CollectionModel @State var showDetails: Bool = false var body: some View { Text("\(collectionModel.randomNumb)") .padding() .frame(width: 200, height: 250) .background(.red.gradient) .clipShape(RoundedRectangle(cornerRadius: 15)) .font(.title) .bold() .foregroundStyle(.white) .onTapGesture { showDetails = true } .sheet(isPresented: $showDetails){ ZStack{ Color.red .ignoresSafeArea() Text("\(collectionModel.randomNumb)") } } } }
尝试的解决方案
改用.sheet(item:)方案
学习相关教程后,将Sheet的触发方式改为.sheet(item:),调整代码如下:
修改后的 ListView
struct ListView: View { var listOfCollectionModel: [CollectionModel] = CollectionModel.mockArray @State var selectedModel: CollectionModel? = nil var body: some View { ScrollView(.horizontal, showsIndicators: false) { LazyHStack{ ForEach(listOfCollectionModel) { model in CollectionView(collectionModel: model) .onTapGesture { selectedModel = model } } }.padding(.horizontal) .sheet(item: $selectedModel) { model in ZStack { Color.black .ignoresSafeArea() Text("\(model.randomNumb)") .font(.title) .bold() .foregroundStyle(.white) } } } } }
修改后的 CollectionView
struct CollectionView: View { @State var collectionModel: CollectionModel var body: some View { Text("\(collectionModel.randomNumb)") .padding() .frame(width: 200, height: 250) .background(.red.gradient) .clipShape(RoundedRectangle(cornerRadius: 15)) .font(.title) .bold() .foregroundStyle(.white) } }
此时弹窗能正常弹出,但偶尔会显示之前选中项目的内容。
添加.id(sheetID)修复
为解决内容显示异常的问题,添加了sheetID来强制刷新Sheet视图:
最终修改的 ListView
struct ListView: View { var listOfCollectionModel: [CollectionModel] = CollectionModel.mockArray @State var selectedModel: CollectionModel? = nil @State var sheetID: UUID = UUID() var body: some View { ScrollView(.horizontal, showsIndicators: false) { LazyHStack{ ForEach(listOfCollectionModel) { model in CollectionView(collectionModel: model) .onTapGesture { selectedModel = model sheetID = UUID() } } }.padding(.horizontal) .sheet(item: $selectedModel) { model in ZStack { Color.black .ignoresSafeArea() Text("\(model.randomNumb)") .font(.title) .bold() .foregroundStyle(.white) }.id(sheetID) } } } }
疑问
目前修改后弹窗看似能正常工作,但感觉这只是通过叠加修复掩盖了初始实现的问题,希望了解问题的本质根源,以及更合理的解决方案。@Benzy Neez的回复有效,但仍想明确问题根源。
内容的提问来源于stack exchange,提问作者Kaiye
相关产品推荐
相关产品推荐

