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

如何在SwiftUI Alert中集成Activity Indicator(活动指示器)?

嘿,这个问题我之前也碰到过——SwiftUI 原生的 Alert 确实没有直接提供添加 Activity Indicator 的接口,不过我们有两种靠谱的实现思路,正好适配你 iOS 14 的场景,我给你详细说说:

方案一:自定义模态视图替代原生 Alert

因为 SwiftUI 原生 Alert 的扩展性很差,自定义一个模态视图是最灵活的方式,完全可以按照你的需求布局,还能保持和原生 Alert 类似的交互逻辑(用遵循 Identifiable 的可选状态来控制显示)。

代码示例如下:

// 定义遵循 Identifiable 的 Alert 状态模型
struct LoadingAlert: Identifiable {
    let id = UUID()
    let message: String
    let isLoading: Bool
}

struct ContentView: View {
    // 用可选类型控制 Alert 显示/隐藏
    @State private var loadingAlert: LoadingAlert?
    
    var body: some View {
        Button("Show Loading Alert") {
            loadingAlert = LoadingAlert(message: "Processing...", isLoading: true)
        }
        // 通过 overlay 实现居中的模态弹窗
        .overlay(
            Group {
                if let alert = loadingAlert {
                    // 半透明背景
                    Color.black.opacity(0.5)
                        .ignoresSafeArea()
                        .overlay(
                            // 弹窗内容卡片
                            VStack(spacing: 16) {
                                Text(alert.message)
                                    .foregroundColor(.black)
                                    .font(.headline)
                                // SwiftUI 自带的活动指示器(iOS 13+ 可用,适配 iOS 14)
                                if alert.isLoading {
                                    ProgressView()
                                        .tint(.blue)
                                }
                                Button("Cancel") {
                                    loadingAlert = nil
                                }
                                .buttonStyle(.borderedProminent)
                            }
                            .padding()
                            .background(Color.white)
                            .cornerRadius(12)
                            .shadow(radius: 10)
                        )
                }
            }
        )
    }
}

这个方案的优势:

  • 完全自定义布局,你可以调整文字样式、指示器位置、按钮样式,甚至添加更多元素
  • 逻辑和原生 Alert 一致,用 Identifiable 的可选状态控制显示,学习成本低
  • 适配 iOS 14,不需要额外的兼容性处理
方案二:桥接 UIKit 的 UIAlertController 实现

既然你提到 UIKit 里可以给 UIAlertController 添加子视图,那我们可以在 SwiftUI 中通过 ViewModifier 来封装这个逻辑,既能利用 UIKit 的灵活性,又能贴近原生 Alert 的样式。

代码示例:

// 自定义 ViewModifier,封装 UIKit Alert 的逻辑
struct LoadingAlertModifier: ViewModifier {
    let message: String
    // 用绑定控制 Alert 显示/隐藏,也可以改成 Identifiable 的可选类型
    @Binding var isPresented: Bool
    
    func body(content: Content) -> some View {
        content
            .onChange(of: isPresented) { newValue in
                if newValue {
                    presentLoadingAlert()
                }
            }
    }
    
    private func presentLoadingAlert() {
        // 获取当前根视图控制器(iOS 14 可用该方式)
        guard let rootVC = UIApplication.shared.windows.first?.rootViewController else { return }
        
        // 创建 UIAlertController
        let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert)
        
        // 添加 Activity Indicator
        let activityIndicator = UIActivityIndicatorView(style: .medium)
        activityIndicator.translatesAutoresizingMaskIntoConstraints = false
        activityIndicator.startAnimating()
        alert.view.addSubview(activityIndicator)
        
        // 设置指示器的居中约束
        NSLayoutConstraint.activate([
            activityIndicator.centerXAnchor.constraint(equalTo: alert.view.centerXAnchor),
            activityIndicator.bottomAnchor.constraint(equalTo: alert.view.bottomAnchor, constant: -20)
        ])
        
        // 添加取消按钮并绑定关闭逻辑
        let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { _ in
            isPresented = false
        }
        alert.addAction(cancelAction)
        
        // 弹出 Alert
        rootVC.present(alert, animated: true)
    }
}

// 给 View 添加扩展,方便调用
extension View {
    func loadingAlert(message: String, isPresented: Binding<Bool>) -> some View {
        self.modifier(LoadingAlertModifier(message: message, isPresented: isPresented))
    }
}

// 使用示例
struct ContentView: View {
    @State private var showAlert = false
    
    var body: some View {
        Button("Show Loading Alert") {
            showAlert = true
        }
        .loadingAlert(message: "Processing...", isPresented: $showAlert)
    }
}

如果想要适配你提到的 Identifiable 可选状态,只需要把 Binding<Bool> 改成 Binding<LoadingAlert?>,然后在 onChange 里判断是否有值即可,逻辑和原生 Alert 完全对齐。

这个方案的优势:

  • 完全复用 UIKit 的原生 Alert 样式,视觉上和系统保持一致
  • 利用你已有的 UIKit 知识,不需要重新设计弹窗布局
总结

如果需要高度自定义弹窗样式,优先选方案一;如果想保持原生 Alert 的视觉风格,方案二更合适。两种方案都能在 iOS 14 上稳定运行,你可以根据自己的需求选择。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 14:22:33