You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
216 lines
9.2 KiB
216 lines
9.2 KiB
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
|
|
|
|
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)
|
|
|
|
// 动态背景粒子效果
|
|
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("MyQrCode")
|
|
.font(.system(size: 42, weight: .bold, design: .rounded))
|
|
.foregroundColor(.white)
|
|
.shadow(color: .black.opacity(0.4), radius: 3, x: 0, y: 2)
|
|
|
|
Text("QR Code Scanner & Generator")
|
|
.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("Professional QR Code Solution")
|
|
.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...")
|
|
.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)
|
|
}
|
|
.onAppear {
|
|
startAnimations()
|
|
}
|
|
}
|
|
|
|
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()
|
|
}
|