import SwiftUI struct LaunchScreenView: View { @State private var isAnimating = false @State private var iconScale: CGFloat = 0.8 @State private var textOpacity: Double = 0.0 @State private var backgroundOpacity: Double = 0.0 @State private var showNetworkPermission = false @StateObject private var networkManager = NetworkPermissionManager() let onLaunchComplete: () -> Void var body: some View { ZStack { // 背景渐变 - 更专业的配色 LinearGradient( gradient: Gradient(colors: [ Color(red: 0.05, green: 0.1, blue: 0.25), Color(red: 0.15, green: 0.25, blue: 0.5), Color(red: 0.25, green: 0.35, blue: 0.7) ]), startPoint: .topLeading, endPoint: .bottomTrailing ) .ignoresSafeArea() .opacity(backgroundOpacity) // 网络权限检查视图 if showNetworkPermission { NetworkPermissionView(networkManager: networkManager) { // 网络权限获取成功,继续启动 showNetworkPermission = false DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { onLaunchComplete() } } .transition(.opacity.combined(with: .scale)) } else { // 正常的启动界面 launchContentView .opacity(showNetworkPermission ? 0 : 1) } } .onAppear { startAnimations() // 延迟检查网络权限 DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) { checkNetworkPermission() } } .onChange(of: networkManager.isNetworkAvailable) { isAvailable in if !isAvailable && !networkManager.isCheckingNetwork { showNetworkPermission = true } } } private var launchContentView: some View { ZStack { // 动态背景粒子效果 ForEach(0..<20) { index in Circle() .fill(Color.white.opacity(0.1)) .frame(width: CGFloat.random(in: 2...6)) .position( x: CGFloat.random(in: 0...UIScreen.main.bounds.width), y: CGFloat.random(in: 0...UIScreen.main.bounds.height) ) .scaleEffect(isAnimating ? 1.5 : 0.5) .opacity(isAnimating ? 0.3 : 0.0) .animation( .easeInOut(duration: Double.random(in: 2...4)) .repeatForever(autoreverses: true) .delay(Double(index) * 0.1), value: isAnimating ) } VStack(spacing: 40) { Spacer() // 应用图标区域 VStack(spacing: 25) { // 应用图标容器 ZStack { // 背景光晕效果 Circle() .fill( RadialGradient( gradient: Gradient(colors: [ Color.white.opacity(0.4), Color.white.opacity(0.1), Color.clear ]), center: .center, startRadius: 30, endRadius: 100 ) ) .frame(width: 180, height: 180) .scaleEffect(isAnimating ? 1.3 : 0.8) .opacity(isAnimating ? 0.7 : 0.0) .animation(.easeInOut(duration: 2.5).repeatForever(autoreverses: true), value: isAnimating) // 主图标容器 RoundedRectangle(cornerRadius: 35) .fill( LinearGradient( gradient: Gradient(colors: [ Color.white.opacity(0.95), Color.white.opacity(0.8) ]), startPoint: .topLeading, endPoint: .bottomTrailing ) ) .frame(width: 140, height: 140) .shadow(color: .black.opacity(0.4), radius: 25, x: 0, y: 15) .scaleEffect(iconScale) .animation(.spring(response: 1.0, dampingFraction: 0.7), value: iconScale) // 应用图标 - 使用系统图标作为主要图标 Image(systemName: "qrcode.viewfinder") .font(.system(size: 60, weight: .medium)) .foregroundStyle( LinearGradient( gradient: Gradient(colors: [ Color.blue, Color.purple ]), startPoint: .topLeading, endPoint: .bottomTrailing ) ) .frame(width: 90, height: 90) .background( RoundedRectangle(cornerRadius: 20) .fill(Color.white.opacity(0.9)) ) .clipShape(RoundedRectangle(cornerRadius: 20)) .shadow(color: .black.opacity(0.2), radius: 10, x: 0, y: 5) .scaleEffect(isAnimating ? 1.1 : 1.0) .animation(.easeInOut(duration: 2.0).repeatForever(autoreverses: true), value: isAnimating) } // 关闭ZStack // 应用名称和描述 VStack(spacing: 15) { Text("app_title".localized) .font(.system(size: 42, weight: .bold, design: .rounded)) .foregroundColor(.white) .shadow(color: .black.opacity(0.4), radius: 3, x: 0, y: 2) Text("app_subtitle".localized) .font(.system(size: 20, weight: .medium)) .foregroundColor(.white.opacity(0.9)) .multilineTextAlignment(.center) .shadow(color: .black.opacity(0.3), radius: 2, x: 0, y: 1) Text("app_description_launch".localized) .font(.system(size: 16, weight: .regular)) .foregroundColor(.white.opacity(0.7)) .multilineTextAlignment(.center) .shadow(color: .black.opacity(0.2), radius: 1, x: 0, y: 1) } .opacity(textOpacity) } Spacer() // 加载指示器 VStack(spacing: 20) { // 进度条 RoundedRectangle(cornerRadius: 3) .fill(Color.white.opacity(0.2)) .frame(width: 250, height: 6) .overlay( RoundedRectangle(cornerRadius: 3) .fill( LinearGradient( gradient: Gradient(colors: [ Color.blue, Color.purple ]), startPoint: .leading, endPoint: .trailing ) ) .frame(width: 250 * (isAnimating ? 1.0 : 0.0), height: 6) .animation(.easeInOut(duration: 2.5), value: isAnimating) ) // 加载状态文本 Text("initializing".localized) .font(.system(size: 16, weight: .medium)) .foregroundColor(.white.opacity(0.8)) .opacity(textOpacity) // 加载点 HStack(spacing: 15) { ForEach(0..<3) { index in Circle() .fill(Color.white) .frame(width: 12, height: 12) .scaleEffect(isAnimating ? 1.3 : 0.8) .opacity(isAnimating ? 1.0 : 0.4) .animation( .easeInOut(duration: 1.0) .repeatForever(autoreverses: true) .delay(Double(index) * 0.25), value: isAnimating ) } } } .opacity(textOpacity) Spacer() } .padding(.horizontal, 40) } } private func checkNetworkPermission() { // 如果网络不可用,显示权限请求界面 if !networkManager.isNetworkAvailable { showNetworkPermission = true } else { // 网络可用,继续启动流程 DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { onLaunchComplete() } } } private func startAnimations() { // 启动背景动画 withAnimation(.easeIn(duration: 1.0)) { backgroundOpacity = 1.0 } // 启动图标动画 withAnimation(.spring(response: 1.0, dampingFraction: 0.7).delay(0.2)) { iconScale = 1.0 } // 启动文本动画 withAnimation(.easeIn(duration: 1.0).delay(0.5)) { textOpacity = 1.0 } // 启动循环动画 withAnimation(.easeIn(duration: 0.1).delay(0.8)) { isAnimating = true } } } #Preview { LaunchScreenView { print("Launch completed") } }