84 lines
3.0 KiB
Swift
84 lines
3.0 KiB
Swift
import SwiftUI
|
||
|
||
struct CustomLightSequenceAnimation: View {
|
||
// 核心循环序列:按"123321123321"规律定义基础单元
|
||
private let baseSequence: [Int] = [1, 2, 3, 3, 2, 1, 1, 2, 3, 3, 2, 1]
|
||
@State private var currentLight: Int = 1 // 当前显示的图片序号
|
||
@State private var sequenceIndex: Int = 0 // 当前在序列中的索引
|
||
|
||
// 淡入淡出透明度控制(确保切换丝滑)
|
||
@State private var currentOpacity: CGFloat = 1.0
|
||
@State private var nextOpacity: CGFloat = 0.0
|
||
|
||
// 尺寸参数(适配正方形卡片)
|
||
private let screenWidth = UIScreen.main.bounds.width
|
||
private let squareSize: CGFloat
|
||
private let imageSize: CGFloat
|
||
|
||
init() {
|
||
self.squareSize = screenWidth * 1.8 // 正方形背景尺寸
|
||
self.imageSize = squareSize / 3 // 光束卡片尺寸(1/3背景大小)
|
||
}
|
||
|
||
// 卡片中心位置(固定,确保摆正居中)
|
||
private var centerPosition: CGPoint {
|
||
CGPoint(x: screenWidth / 2, y: squareSize * 0.325)
|
||
}
|
||
|
||
var body: some View {
|
||
ZStack {
|
||
// 底部背景(正方形)
|
||
SVGImage(svgName: "BlindBg")
|
||
.frame(width: squareSize, height: squareSize)
|
||
.position(centerPosition)
|
||
|
||
// 当前显示的光束卡片(摆正状态)
|
||
SVGImage(svgName: "Light\(currentLight)")
|
||
.frame(width: imageSize, height: imageSize)
|
||
.position(centerPosition)
|
||
.opacity(currentOpacity)
|
||
|
||
// 下一张待显示的光束卡片(提前加载,摆正状态)
|
||
SVGImage(svgName: "Light\(nextLight)")
|
||
.frame(width: imageSize, height: imageSize)
|
||
.position(centerPosition)
|
||
.opacity(nextOpacity)
|
||
}
|
||
.onAppear {
|
||
startLoopAnimation()
|
||
}
|
||
}
|
||
|
||
// 计算下一张卡片序号(基于当前索引循环)
|
||
private var nextLight: Int {
|
||
let nextIdx = (sequenceIndex + 1) % baseSequence.count
|
||
return baseSequence[nextIdx]
|
||
}
|
||
|
||
// 启动循环切换动画
|
||
private func startLoopAnimation() {
|
||
// 每1.2秒切换一次(可调整速度)
|
||
Timer.scheduledTimer(withTimeInterval: 1.2, repeats: true) { _ in
|
||
// 0.5秒淡入淡出过渡(丝滑无卡顿)
|
||
withAnimation(Animation.easeInOut(duration: 0.5)) {
|
||
currentOpacity = 0.0
|
||
nextOpacity = 1.0
|
||
}
|
||
|
||
// 动画完成后更新状态(确保顺序无偏差)
|
||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
||
currentLight = nextLight
|
||
sequenceIndex = (sequenceIndex + 1) % baseSequence.count
|
||
currentOpacity = 1.0
|
||
nextOpacity = 0.0
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 预览
|
||
struct CustomLightSequenceAnimation_Previews: PreviewProvider {
|
||
static var previews: some View {
|
||
CustomLightSequenceAnimation()
|
||
}
|
||
} |