Flutter集成SwiftUI雪花动画:解决导航切换时Timer重复创建问题
解决SwiftUI雪花动画Timer重复运行导致的加速异常
当前实现中,通过UiKitView加载的SnowFallAnimationView每次显示时,onAppear都会触发startSnowFall创建新Timer,导航离开页面时旧Timer未被销毁,返回后多个Timer叠加运行,导致雪花位置被多次更新,出现持续加速的异常效果。以下是两种针对性解决方案:
方案一:页面消失时停止Timer
利用SwiftUI的onDisappear修饰符,在页面离开时停止Timer,彻底终止后台运行的定时器,避免残留Timer继续影响动画状态。
修改后的完整SwiftUI代码:
import SwiftUI struct Snowflake: Identifiable { var id = UUID() var x: Double var y: Double var scale: Double var speed: Double } struct SnowFallAnimationView: View{ @State private var snowflakes: [Snowflake] = [] @State private var timer: Timer? var body: some View { ZStack { LinearGradient( gradient: Gradient(colors: [.black, .black]), startPoint: .top, endPoint: .bottom ) if #available(iOS 15.0, *) { Canvas { context, size in for snowflake in snowflakes { context.draw( Text("❄️").font(.system(size: 10 * snowflake.scale)), at: CGPoint(x: snowflake.x * size.width, y: snowflake.y * size.height) ) } } } } .onAppear() { startSnowFall() } .onDisappear() { stopSnowFall() } } func startSnowFall() { // 仅在雪花数据为空时初始化 if snowflakes.isEmpty { for _ in 0..<50 { snowflakes.append( Snowflake( x: Double.random(in: 0...1), y: Double.random(in: -0.2...0), scale: Double.random(in: 0.5...1.5), speed: Double.random(in: 0.001...0.003) ) ) } } // 创建新Timer前先停止旧Timer timer?.invalidate() timer = Timer.scheduledTimer(withTimeInterval: 0.016, repeats: true) { _ in for i in snowflakes.indices { snowflakes[i].y += snowflakes[i].speed if snowflakes[i].y >= 1.2 { snowflakes[i].y = -0.2 snowflakes[i].x = Double.random(in: 0...1) } } } } func stopSnowFall() { timer?.invalidate() timer = nil // 可选:重置雪花位置,下次进入页面重新开始动画 // snowflakes.removeAll() } }
方案二:复用已存在的Timer,避免重复创建
在startSnowFall中先检查Timer是否处于运行状态,仅在未运行时创建新Timer,同时确保雪花数据只初始化一次,从根源上避免多Timer叠加。
核心修改逻辑:
func startSnowFall() { // 初始化雪花数据(仅执行一次) if snowflakes.isEmpty { for _ in 0..<50 { snowflakes.append( Snowflake( x: Double.random(in: 0...1), y: Double.random(in: -0.2...0), scale: Double.random(in: 0.5...1.5), speed: Double.random(in: 0.001...0.003) ) ) } } // Timer已运行则直接返回,避免重复创建 guard timer == nil || !timer!.isValid else { return } // 创建新Timer timer = Timer.scheduledTimer(withTimeInterval: 0.016, repeats: true) { _ in for i in snowflakes.indices { snowflakes[i].y += snowflakes[i].speed if snowflakes[i].y >= 1.2 { snowflakes[i].y = -0.2 snowflakes[i].x = Double.random(in: 0...1) } } } }
同时保留onDisappear的停止逻辑,确保页面离开时释放资源:
.onDisappear() { timer?.invalidate() timer = nil }
补充说明
- 两种方案结合使用效果最优:离开页面停止Timer避免后台资源浪费,进入时检查Timer状态避免重复创建。
- Flutter侧代码无需修改,
UiKitView的生命周期会与Flutter页面同步,自动触发SwiftUI的onAppear和onDisappear回调。
内容的提问来源于stack exchange,提问作者Aks
相关产品推荐
相关产品推荐

