SwiftUI Sheet多次调用问题:内容重复生成及闪烁现象咨询
SwiftUI Sheet重复实例生成问题及解决方法
问题场景
开发SwiftUI跨平台应用时,点击按钮打开Sheet,传入的参数由生成Sheet内容数组的方法提供。发现点击按钮时内容会生成三次,iOS端无明显表现,但macOS端关闭Sheet时会短暂出现另外两个实例,造成Sheet闪烁。简化代码后,点击按钮时仍会执行两次,需要实现内容和视图仅生成一次。
简化代码示例
ContentView
import SwiftUI struct ContentView: View { private enum Destinations { case empty } @State private var selection: Destinations? @State private var showSheet = false var body: some View { NavigationSplitView { List(selection: $selection) { Section(content: { Button(action: { showSheet = true }, label: { Label { Text("Generate and Open") } icon: { Image(systemName: "doc.plaintext") } }) }, header: { Text("This Section") }) .sheet(isPresented: $showSheet) { SheetView(showQuiz: $showSheet, questionSTr: generateValueToPassIn()) .onAppear(){ print("in on appear sheet") } } } // List End .navigationTitle("Quiz") #if os(iOS) .listStyle(.insetGrouped) #endif } detail: { NavigationStack { switch selection ?? .empty { case .empty: Text("Please select an option to continue.") } } } } private func generateValueToPassIn() -> String { print("In here; should be once") return "this string" } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }
SheetView
import SwiftUI struct SheetView: View { // 父子视图共用的变量 @Binding var showQuiz: Bool @State var questionSTr: String init(showQuiz: Binding<Bool>, questionSTr: String) { print("In sheet INIT") _showQuiz = showQuiz self.questionSTr = questionSTr } var body: some View { VStack(alignment: .center) { Text(questionSTr) Button() { showQuiz = false } label: { Text("Exit Quiz") } } } } struct SheetView_Previews: PreviewProvider { static var previews: some View { SheetView(showQuiz: .constant(true), questionSTr: "test") } }
解决方法
将生成Sheet参数的耗时逻辑移至外部,仅执行一次。具体来说,在点击按钮触发Sheet显示时,先调用生成参数的方法并保存结果,再将保存好的参数传入Sheet,避免在Sheet初始化时直接调用生成方法(SwiftUI视图更新时会重复执行该方法)。
修改后的核心逻辑示例:
// 在ContentView中添加@State存储生成的参数 @State private var generatedString: String = "" // 按钮点击时先生成参数再显示Sheet Button(action: { generatedString = generateValueToPassIn() showSheet = true }, label: { Label { Text("Generate and Open") } icon: { Image(systemName: "doc.plaintext") } }) // Sheet初始化时传入已生成好的参数 .sheet(isPresented: $showSheet) { SheetView(showQuiz: $showSheet, questionSTr: generatedString) .onAppear(){ print("in on appear sheet") } }
这样就能确保参数仅生成一次,Sheet也只会初始化一次,解决macOS端的闪烁问题。
内容的提问来源于stack exchange,提问作者Kyra
相关产品推荐
相关产品推荐

