Blame view

lib/common/widgets/speaker_widget.dart 3.67 KB
56b412f5   吴启风   feat:扬声器播放动画组件封装
1
2
3
4
  import 'package:flutter/material.dart';
  import 'dart:async';
  
  import 'package:wow_english/common/extension/string_extension.dart';
d4d91cb0   吴启风   feat:lottie动效组件封装...
5
6
7
  import 'package:wow_english/common/widgets/throttledGesture_gesture_detector.dart';
  
  import '../../utils/log_util.dart';
56b412f5   吴启风   feat:扬声器播放动画组件封装
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
  
  /// 扬声器播放组件,帧动画
  class SpeakerWidget extends StatefulWidget {
    final bool isPlaying;
    final bool isClickable;
    final double width;
    final double height;
    final VoidCallback? onTap;
  
    SpeakerWidget({
      super.key,
      this.isPlaying = false,
      this.isClickable = true,
      required this.width,
      required this.height,
      this.onTap,
    });
  
    @override
    _SpeakerWidgetState createState() => _SpeakerWidgetState();
  }
  
  class _SpeakerWidgetState extends State<SpeakerWidget>
      with SingleTickerProviderStateMixin {
    late AnimationController _controller;
    int _currentFrame = 0;
    Timer? _timer;
    final List<String> _speakerImagePaths = [
      'ic_speaker_play2'.assetPng,
      'ic_speaker_play0'.assetPng,
      'ic_speaker_play1'.assetPng,
    ];
d4d91cb0   吴启风   feat:lottie动效组件封装...
40
41
42
    static const String TAG = "SpeakerWidget";
  
    bool _isPlaying = false;
56b412f5   吴启风   feat:扬声器播放动画组件封装
43
44
45
46
47
48
49
50
51
  
    @override
    void initState() {
      super.initState();
      _controller = AnimationController(
        duration: const Duration(milliseconds: 300), // 每帧的持续时间
        vsync: this,
      );
  
e0e89ade   吴启风   feat:选择选项组件动画防抖
52
53
      Log.d(
          "$TAG ${identityHashCode(this)} initState widget=${widget.isPlaying} _isPlaying=$_isPlaying _controller=${identityHashCode(_controller)}");
56b412f5   吴启风   feat:扬声器播放动画组件封装
54
      if (widget.isPlaying) {
819ae43b   吴启风   feat:体验优化-练习题目取消阻...
55
56
57
58
        ///fixme 增加200毫秒延迟,避免一进入就已经开始播了,效果有待观察
        Future.delayed(const Duration(milliseconds: 200), () {
          _startAnimation();
        });
56b412f5   吴启风   feat:扬声器播放动画组件封装
59
60
61
62
63
64
      }
    }
  
    @override
    void didUpdateWidget(SpeakerWidget oldWidget) {
      super.didUpdateWidget(oldWidget);
d4d91cb0   吴启风   feat:lottie动效组件封装...
65
      Log.d(
e0e89ade   吴启风   feat:选择选项组件动画防抖
66
          "$TAG ${identityHashCode(this)} didUpdateWidget widget=${widget.isPlaying} oldWidget=${oldWidget.isPlaying} _isPlaying=$_isPlaying");
d4d91cb0   吴启风   feat:lottie动效组件封装...
67
68
69
70
71
72
73
      if (widget.isPlaying && !_isPlaying) {
        setState(() {
          _isPlaying = true;
        });
        _startAnimation();
      } else if (!widget.isPlaying && _isPlaying) {
        _stopAnimation();
56b412f5   吴启风   feat:扬声器播放动画组件封装
74
75
76
77
      }
    }
  
    void _startAnimation() {
642081ad   吴启风   feat:lottie动画加载优化...
78
      Log.d(
e0e89ade   吴启风   feat:选择选项组件动画防抖
79
          "$TAG ${identityHashCode(this)} _startAnimation widget=${widget.isPlaying} _isPlaying=$_isPlaying isAnimating=${_controller.isAnimating}");
56b412f5   吴启风   feat:扬声器播放动画组件封装
80
      _timer = Timer.periodic(const Duration(milliseconds: 300), (Timer timer) {
0ebc6186   吴启风   feat:解决异步场景下setSt...
81
82
83
84
85
        if (mounted) {
          setState(() {
            _currentFrame = ((_currentFrame + 1) % 3);
          });
        }
56b412f5   吴启风   feat:扬声器播放动画组件封装
86
87
88
89
      });
    }
  
    void _stopAnimation() {
642081ad   吴启风   feat:lottie动画加载优化...
90
      Log.d(
e0e89ade   吴启风   feat:选择选项组件动画防抖
91
          "$TAG ${identityHashCode(this)} _stopAnimation widget=${widget.isPlaying} _isPlaying=$_isPlaying isAnimating=${_controller.isAnimating}");
56b412f5   吴启风   feat:扬声器播放动画组件封装
92
      _timer?.cancel();
642081ad   吴启风   feat:lottie动画加载优化...
93
94
95
      _controller.stop();
      _controller.reset();
  
0ebc6186   吴启风   feat:解决异步场景下setSt...
96
97
98
99
100
101
      if (mounted) {
        setState(() {
          _isPlaying = false;
          _currentFrame = 0;
        });
      }
56b412f5   吴启风   feat:扬声器播放动画组件封装
102
103
104
105
    }
  
    @override
    void dispose() {
e0e89ade   吴启风   feat:选择选项组件动画防抖
106
107
      Log.d(
          "$TAG ${identityHashCode(this)} dispose widget=${widget.isPlaying} _isPlaying=$_isPlaying isAnimating=${_controller.isAnimating}");
56b412f5   吴启风   feat:扬声器播放动画组件封装
108
109
110
111
112
113
114
      _controller.dispose();
      _timer?.cancel();
      super.dispose();
    }
  
    @override
    Widget build(BuildContext context) {
d4d91cb0   吴启风   feat:lottie动效组件封装...
115
      return ThrottledGestureDetector(
56b412f5   吴启风   feat:扬声器播放动画组件封装
116
        onTap: widget.isClickable ? widget.onTap : null,
d4d91cb0   吴启风   feat:lottie动效组件封装...
117
118
119
120
121
122
123
124
125
126
127
        child: Opacity(
          opacity: widget.isClickable ? 1.0 : 0.5,
          child: Image.asset(
            _speakerImagePaths[_currentFrame],
            width: widget.width,
            height: widget.height,
            fit: BoxFit.cover,
            color: widget.isClickable ? null : Colors.transparent,
            // 灰色遮罩
            colorBlendMode: widget.isClickable ? null : BlendMode.saturation,
          ),
56b412f5   吴启风   feat:扬声器播放动画组件封装
128
129
130
131
        ),
      );
    }
  }