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 RecorderPlaybackWidget extends StatefulWidget { final bool isClickable; final bool isPlaying; final VoidCallback? onTap; final double width; final double height; const RecorderPlaybackWidget({ Key? key, required this.isClickable, required this.isPlaying, required this.onTap, required this.width, required this.height, }) : super(key: key); @override _RecorderPlaybackWidgetState createState() => _RecorderPlaybackWidgetState(); } class _RecorderPlaybackWidgetState extends State with SingleTickerProviderStateMixin { late final AnimationController _controller; late final Future _futureComposition; static const String TAG = "RecorderPlaybackWidget"; bool _isPlaying = false; @override void initState() { super.initState(); _controller = AnimationController(vsync: this); _loadComposition(); if (widget.isPlaying) { _playAnimation(); } _controller.addListener(() { // Log.d("$TAG addListener _controller=${_controller.status}"); }); } @override void didUpdateWidget(RecorderPlaybackWidget oldWidget) { super.didUpdateWidget(oldWidget); Log.d( "$TAG ${identityHashCode(this)} didUpdateWidget widget=${widget.isPlaying} oldWidget=${oldWidget.isPlaying} _isPlaying=$_isPlaying"); if (widget.isPlaying && !_isPlaying) { setState(() { _isPlaying = true; }); _playAnimation(); } else if (!widget.isPlaying && _isPlaying) { _stopAnimation(); } if (!_isPlaying) { _displayAnimation(widget.isClickable); } } Future _loadComposition() async { _futureComposition = AssetLottie('assets/lotties/recorder_playback.zip').load(); } void _playAnimation() { _controller.reset(); _futureComposition.then((composition) { _controller.duration = composition.duration; _controller.repeat( min: 2 / composition.endFrame, max: 20 / composition.endFrame, ); }); } void _stopAnimation() { _controller.stop(); if (mounted) { setState(() { _isPlaying = false; _futureComposition.then((composition) { _controller.value = 1 / composition.endFrame; }); // _controller.repeat( // min: 1 / _composition.endFrame, // max: 1 / _composition.endFrame, // ); }); } } void _displayAnimation(bool clickable) { if (clickable) { _controller.value = 1; // _controller.repeat( // min: 1, // max: 1, // ); } else { _controller.value = 0; // _controller.repeat( // min: 0, // max: 0, // ); } } @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: FutureBuilder( future: _futureComposition, builder: (context, snapshot) { if (snapshot.hasData) { final composition = snapshot.data!; return Lottie( composition: composition, controller: _controller, renderCache: RenderCache.raster, width: widget.width, height: widget.height, ); } else { return const SizedBox.shrink(); } }), ), ); } }