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

SwiftUI中ProgressView在任务完成后才显示的问题求助

SwiftUI点击ProjectItem无法提前显示ProgressView问题解决

问题描述

我有一个SwiftUI视图ProjectItem,点击时本该显示ProgressView作为加载提示,但实际只有在文档加载完成后才会显示。点击后打开文档需要几秒时间,我希望能立刻向用户展示加载状态。

相关代码

ProjectItem视图代码

struct ProjectItem: View {
@EnvironmentObject var controller: ProjectController
@State var showLoadingIcon: Bool = false
let document: Document

var body: some View {
    VStack {
        ZStack {
        Text(document.name).font(Interface.Text.PopoverDialogLabel)
        Text(document.editTime.toString(true)).font(.caption2).foregroundColor(.gray)
        if showLoadingIcon {
            ProgressView()
        }
    }
    .padding(Interface.Sizes.StandardPadding)
    .if(controller.editedDocumentID == nil) { $0.onTapGesture(count: 1, perform: {
                // Open Project
                showLoadingIcon = true // 这行代码实际在TransitionView之后执行
                controller.openDocument(document: document)
                TransitionView() // 这行在ProgressView显示前执行
    })}
}

ProjectController中的openDocument方法

func openDocument(document: Document) {
    app.setProject(document.id) // 该操作耗时几秒,且当前必须运行在主线程
}

尝试过的无效方案

  • 将controller.openDocument(document: document)和TransitionView()包装进Task{}
  • 将openDocument设为异步/同步调用

禁用TransitionView后通过断点发现,controller.openDocument执行完成后,才会检查showLoadingIcon的值并显示ProgressView。

解决方法

核心问题是app.setProject阻塞主线程,导致SwiftUI无法立即刷新视图更新showLoadingIcon状态。我们需要先让视图完成渲染,再执行耗时操作,同时修正TransitionView的展示逻辑。

修改后的onTapGesture逻辑

.if(controller.editedDocumentID == nil) { $0.onTapGesture(count: 1, perform: {
    // 1. 立即标记加载状态,触发视图刷新
    showLoadingIcon = true
    
    // 2. 让主线程先完成视图渲染,再执行耗时操作
    DispatchQueue.main.async {
        controller.openDocument(document: document)
        // 加载完成后可关闭加载状态(按需选择)
        showLoadingIcon = false
        // 3. 通过状态变量控制TransitionView展示,而非直接创建视图
        controller.shouldShowTransition = true
    }
})}

修正TransitionView的展示方式

直接在闭包里创建TransitionView()无法正确触发展示,需要通过状态变量控制:

  1. 在ProjectController中添加状态:
class ProjectController: ObservableObject {
    // ...其他已有属性
    @Published var shouldShowTransition = false
}
  1. 在合适的位置(如父视图或当前视图的body中)添加:
if controller.shouldShowTransition {
    TransitionView()
        .onDisappear {
            controller.shouldShowTransition = false
        }
}

原理说明

  • showLoadingIcon = true会立即触发SwiftUI的视图更新流程
  • DispatchQueue.main.async将耗时操作推迟到当前主循环的下一轮执行,让SwiftUI有足够时间先渲染出ProgressView,再执行阻塞主线程的app.setProject

内容的提问来源于stack exchange,提问作者Osian

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 05:46:09