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

NavigationStack加载Sheet时出现微卡顿问题求助

大家好,我最近在做SwiftUI项目时遇到了一个小困扰——当我通过sheet弹出包含NavigationStack的NewContactSheet视图时,总会出现轻微的卡顿感,流畅度不太理想。我把相关的代码都贴在下面了,想请教一下社区的大佬们,有没有人能帮忙排查下问题所在,或者给点优化的思路呀?

首先是触发Sheet的代码:

.sheet(isPresented: $newContactSheetTrigger) {
    NewContactSheet()
        .presentationDetents([.large])
}

然后是NewContactSheet的完整实现:

import SwiftUI
import SwiftData
import WidgetKit

struct NewContactSheet: View {
    @Environment(\.dismiss) private var dismiss
    @State private var contactName = ""
    @State private var newDaysDue: Set<String> = []
    @State private var favorite = false
    
    private let templatesHeight = UIScreen.main.bounds.height * 0.035
    private let dayWidth = UIScreen.main.bounds.width * 0.1
    private let weekdays: [String] = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
    private let buttonBackground = Color(uiColor: .systemGroupedBackground)
    private let green85 = Color.green.opacity(0.85)
    private let green30 = Color.green.opacity(0.3)
    private let adaptiveBlack = Color("AdaptiveBlack")
    
    var body: some View {
        NavigationStack {
            Form {
                Section {
                    TextField("Contact name", text: $contactName)
                    
                    HStack {
                        Text("Templates:")
                            .font(.footnote)
                            .foregroundStyle(.secondary)
                        
                        ScrollView(.horizontal, showsIndicators: false) {
                            LazyHStack {
                                ForEach(NewContactTemplate.predefinedTemplates) { template in
                                    Button {
                                        if contactName == template.name {
                                            clearTemplate()
                                        } else {
                                            applyTemplate(template: template)
                                        }
                                    } label: {
                                        Text("\(template.name)")
                                            .padding(.horizontal)
                                            .font(.footnote)
                                            .frame(height: templatesHeight)
                                            .foregroundStyle(adaptiveBlack)
                                    }
                                    .background(buttonBackground, in: RoundedRectangle(cornerRadius: 10))
                                    .buttonStyle(.borderless)
                                }
                            }
                        }
                    }
                    .contentMargins(.horizontal, 0)
                } header: {
                    Text("Name")
                }
                
                Section {
                    HStack (alignment: .center) {
                        Spacer()
                        ForEach (weekdays, id: \.self) { day in
                            let containsCheck = newDaysDue.contains(day)
                            Button {
                                if favorite {
                                    // activeAlert = .correctDaysSelector
                                    // showAlert = true
                                } else {
                                    if containsCheck {
                                        newDaysDue.remove(day)
                                    } else {
                                        newDaysDue.insert(day)
                                    }
                                }
                            } label: {
                                Text(day)
                                    .font(.caption)
                                    .frame(width: dayWidth, height: templatesHeight)
                                    .background(
                                        containsCheck ?
                                        RoundedRectangle(cornerRadius: 10)
                                            .fill(green85)
                                            .overlay(
                                                RoundedRectangle(cornerRadius: 10)
                                                    .stroke(.clear, lineWidth: 2)
                                            ) :
                                        RoundedRectangle(cornerRadius: 10)
                                            .fill(.clear)
                                            .overlay(
                                                RoundedRectangle(cornerRadius: 10)
                                                    .stroke(green30, lineWidth: 2)
                                            )
                                    )
                                    .foregroundStyle(favorite ? .gray : containsCheck ? .white : green85)
                            }
                            .buttonStyle(.plain)
                        }
                        Spacer()
                    }
                    
                    HStack {
                        Text("Presets:")
                            .font(.footnote)
                            .foregroundStyle(.secondary)
                        
                        ScrollView(.horizontal, showsIndicators: false) {
                            LazyHStack {
                                ForEach(NewContactDaysDue.predefinedTemplates) { template in
                                    Button {
                                        if newDaysDue.count == template.daycount {
                                            newDaysDue = []
                                        } else {
                                            newDaysDue = template.daysDue
                                        }
                                    } label: {
                                        Text("\(template.name)")
                                            .padding(.horizontal)
                                            .font(.footnote)
                                            .frame(height: templatesHeight)
                                            .foregroundStyle(adaptiveBlack)
                                    }
                                    .buttonStyle(.borderless)
                                    .background(buttonBackground, in: RoundedRectangle(cornerRadius: 10))
                                }
                            }
                        }
                    }
                    .contentMargins(.horizontal, 0)
                } header: {
                    Text("Meet")
                }
                
                Section {} header: { Text("xxx") }
                Section {} header: { Text("xxx") }
                Section {} header: { Text("xxx") }
                Section {} header: { Text("xxx") }
                Section {} header: { Text("xxx") }
                Section {} header: { Text("xxx") }
                Section {} header: { Text("xxx") }
                Section {} header: { Text("xxx") }
            }
            .scrollIndicators(.hidden)
            .toolbar {
                ToolbarItem(placement: .topBarLeading) {
                    Button {
                        dismiss()
                    } label: {
                        Text("Cancel")
                            .foregroundStyle(.red)
                    }
                }
                
                ToolbarItem(placement: .topBarTrailing) {
                    Button {
                        //implement save logic
                        WidgetCenter.shared.reloadAllTimelines()
                        dismiss()
                    } label: {
                        Text("Save")
                            .foregroundStyle(.green)
                    }
                }
            }
            .navigationTitle("New Contact")
            .navigationBarTitleDisplayMode(.inline)
            .navigationBarHidden(false)
        }
    }
    
    func applyTemplate(template: NewContactTemplate) {
        contactName = template.name
    }
    
    func clearTemplate() {
        contactName = ""
    }
}

#Preview {
    NewContactSheet()
}

struct NewContactTemplate: Identifiable {
    let id = UUID()
    let name: String
    let daysDue: Set<String>
}

extension NewContactTemplate {
    static let predefinedTemplates: [NewContactTemplate] = [
        NewContactTemplate(name: "Test1", daysDue: ["Mon", "Tue", "Wed"]),
        NewContactTemplate(name: "Test2", daysDue: ["Tue", "Wed", "Fri"]),
        NewContactTemplate(name: "Test3", daysDue: ["Sat", "Sun", "Mon"])
    ]
}

struct NewContactDaysDue: Identifiable {
    let id = UUID()
    let name: String
    let daysDue: Set<String>
    let daycount: Int
}

extension NewContactDaysDue {
    static let predefinedTemplates: [NewContactDaysDue] = [
        NewContactDaysDue(name: "Daily", daysDue: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"], daycount: 7),
        // 原代码此处有截断,保持原样未补充
    ]
}

我自己猜测是不是NavigationStack嵌套Form的结构在初始化时渲染压力有点大?或者有没有什么像延迟加载、预渲染之类的小技巧能缓解这个卡顿问题呀?麻烦大家帮忙看看啦,谢谢!

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.07 09:03:07