代码之家  ›  专栏  ›  技术社区  ›  Aks

如何在导航到其他屏幕时销毁计时器

  •  1
  • Aks  · 技术社区  · 5 月前

    使用UiKitView在flutter应用程序中显示swift UI代码。

    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: UnitPoint.bottom
                )
                //.ignore safe area
                
                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))
                        }
                    }
                } else {
                    // Fallback on earlier versions
                }
            }.onAppear() {
                startSnowFall()
            }
        }
        func startSnowFall() {
            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.scheduledTimer(withTimeInterval: 0.016, repeats: true, block:     {
                _ 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)
                    }
                }
            })
        }
    }
    
    

    扑通一声。

    class NativeViewExample extends StatefulWidget {
      const NativeViewExample({super.key});
    
      @override
      State<NativeViewExample> createState() => _NativeViewExampleState();
    }
    
    class _NativeViewExampleState extends State<NativeViewExample> {
      @override
      Widget build(BuildContext context) {
        const String viewType = '<platform-view-type>';
        // Pass parameters to the platform side.
        final Map<String, dynamic> creationParams = <String, dynamic>{};
        return Stack(
          children: [
            UiKitView(
              viewType: viewType,
              layoutDirection: TextDirection.ltr,
              creationParams: creationParams,
              creationParamsCodec: const StandardMessageCodec(),
            ),
            Align(
              alignment: Alignment.bottomCenter,
              child: Padding(
                padding: const EdgeInsets.all(16.0),
                child: ElevatedButton(
                  onPressed: () {
                    // Flutter button functionality
                    print("Flutter button pressed");
                  },
                  child: Text('Flutter Button'),
                ),
              ),
            ),
          ],
        );
      }
    }
    

    问题是:每次SnowFallAnimationView出现在屏幕上时,都会创建计时器。这会导致多个计时器同时运行,从而导致雪花随着时间的推移而加速。(当导航到另一个屏幕并返回时会发生这种情况)。

    当导航到另一个屏幕时,有什么方法可以停止计时器(以swift代码)吗。或者,只需使用已创建的计时器即可。(防止创建多个计时器)。

    1 回复  |  直到 5 月前
        1
  •  2
  •   sonle    5 月前

    .appear 可以在视图生命周期内多次调用。因此,您应该创建一次计时器,以防止重复并使计时器无效 .disappear ,类似于:

    var body: some View {
        ...
        .onAppear {
            startSnowFall()
        }
        .onDisappear {
            stopSnowFall()
        }
    }
    
    func startSnowFall() {
        guard timer == nil else { return }
        ...
    }
    
    func stopSnowFall() {
        guard timer != nil else { return }
        timer?.invalidate()
        timer = nil
        snowflakes.removeAll()
    }