You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 13:07:25