// // ToastCenter.swift // suixinkan // // Created by Codex on 2026/6/18. // import Observation import SwiftUI @MainActor @Observable /// 全局 Toast 状态中心,负责保存和清除当前提示文案。 final class ToastCenter { fileprivate var message: String? /// 显示一条全局 Toast 文案。 func show(_ message: String) { self.message = message } /// 清除当前 Toast 文案。 func dismiss() { message = nil } } /// 全局 Toast 叠加层修饰器,负责把 Toast 展示到页面顶部。 private struct GlobalToastOverlay: ViewModifier { @Environment(ToastCenter.self) private var toastCenter func body(content: Content) -> some View { content .overlay(alignment: .top) { if let message = toastCenter.message { HStack(spacing: 10) { Image(systemName: "exclamationmark.triangle.fill") .font(.system(size: 14, weight: .semibold)) Text(message) .font(.system(size: 13, weight: .medium)) .lineLimit(2) Spacer(minLength: 0) Button("关闭") { toastCenter.dismiss() } .font(.system(size: 13, weight: .semibold)) } .foregroundStyle(.white) .padding(.horizontal, 14) .padding(.vertical, 10) .background(Color.black.opacity(0.78), in: RoundedRectangle(cornerRadius: 12)) .padding(.horizontal, 16) .padding(.top, 10) .transition(.move(edge: .top).combined(with: .opacity)) } } .animation(.easeInOut(duration: 0.18), value: toastCenter.message) } } extension View { /// 给任意根视图追加全局 Toast 展示能力。 func globalToastOverlay() -> some View { modifier(GlobalToastOverlay()) } }