Blame view

lib/common/widgets/recorder_widget.dart 3.02 KB
d4d91cb0   吴启风   feat:lottie动效组件封装...
1
2
3
4
5
6
7
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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
  import 'package:flutter/material.dart';
  import 'package:lottie/lottie.dart';
  import 'package:wow_english/common/widgets/throttledGesture_gesture_detector.dart';
  
  import '../../utils/log_util.dart';
  
  /// 录音组件
  class RecorderWidget extends StatefulWidget {
    final bool isClickable;
    final bool isPlaying;
    final VoidCallback? onTap;
    final double width;
    final double height;
  
    const RecorderWidget({
      Key? key,
      required this.isClickable,
      required this.isPlaying,
      required this.onTap,
      required this.width,
      required this.height,
    }) : super(key: key);
  
    @override
    _RecorderWidgetState createState() => _RecorderWidgetState();
  }
  
  class _RecorderWidgetState extends State<RecorderWidget>
      with SingleTickerProviderStateMixin {
    late final AnimationController _controller;
    late final LottieComposition _composition;
    static const String TAG = "RecorderWidget";
  
    bool _isPlaying = false;
  
    @override
    void initState() {
      super.initState();
      _controller = AnimationController(vsync: this);
      _loadComposition();
  
      _controller.addListener(() {
        // Log.d("$TAG addListener _controller=${_controller.status}");
      });
    }
  
    Future<void> _loadComposition() async {
      final composition = await AssetLottie('assets/lotties/recorder_input.zip').load();
      setState(() {
        _composition = composition;
        _controller.duration = _composition.duration;
      });
  
      if (widget.isPlaying) {
        _playInitialAnimation();
      }
    }
  
    void _playInitialAnimation() {
      _controller.reset();
      _controller
          .animateTo(22 / _composition.endFrame)
          .whenComplete(() => _loopMiddleAnimation());
    }
  
    void _loopMiddleAnimation() {
      _controller.repeat(
        min: 22 / _composition.endFrame,
        max: 37 / _composition.endFrame,
      );
    }
  
    void _playFinalAnimation() {
      _controller.stop();
      _controller
          .animateTo(50 / _composition.endFrame)
          .whenComplete(() => _resetAnimation());
    }
  
    void _resetAnimation() {
      setState(() {
        _isPlaying = false;
        _controller.value = 0;
      });
    }
  
    @override
    void didUpdateWidget(RecorderWidget oldWidget) {
      super.didUpdateWidget(oldWidget);
      Log.d("$TAG didUpdateWidget widget=${widget.isPlaying} oldWidget=${oldWidget.isPlaying} _isPlaying=$_isPlaying");
      if (widget.isPlaying && !_isPlaying) {
        setState(() {
          _isPlaying = true;
        });
        _playInitialAnimation();
      } else if (!widget.isPlaying && _isPlaying) {
        _playFinalAnimation();
      }
    }
  
    @override
    void dispose() {
      _controller.dispose();
      super.dispose();
    }
  
    @override
    Widget build(BuildContext context) {
      return ThrottledGestureDetector(
        onTap: widget.isClickable ? widget.onTap : null,
        child: Opacity(
          opacity: widget.isClickable ? 1.0 : 0.5, // 设置透明度
          child: Lottie(
            composition: _composition,
            controller: _controller,
            renderCache: RenderCache.raster,
            width: widget.width,
            height: widget.height,
          ),
        ),
      );
    }
  }