import 'package:flutter/material.dart'; import 'package:flutter_svga/flutter_svga.dart'; import 'package:yumi/ui_kit/components/sc_tts.dart'; import 'package:yumi/shared/tools/sc_gift_vap_svga_manager.dart'; class SVGAHeadwearWidget extends StatefulWidget { // 资源路径(网络URL或本地assets路径) final String resource; // 尺寸 final double? width; final double? height; // 动画控制参数 final bool autoPlay; final int loops; // 循环次数(0表示无限循环) final bool clearsAfterStop; // 缓存控制 final bool useCache; // 回调函数 final VoidCallback? onCompleted; final Function(String)? onError; final VoidCallback? onStartLoading; final VoidCallback? onFinishLoading; const SVGAHeadwearWidget({ Key? key, required this.resource, this.width, this.height, this.autoPlay = true, this.loops = 0, this.clearsAfterStop = true, this.useCache = true, this.onCompleted, this.onError, this.onStartLoading, this.onFinishLoading, }) : super(key: key); @override _SVGAHeadwearWidgetState createState() => _SVGAHeadwearWidgetState(); } class _SVGAHeadwearWidgetState extends State with SingleTickerProviderStateMixin { SVGAAnimationController? _animationController; MovieEntity? _retainedMovieEntity; String? _retainedResource; bool _isLoading = true; bool _isNetworkResource = false; bool _hasError = false; @override void initState() { super.initState(); _isNetworkResource = widget.resource.startsWith('http'); _animationController = SVGAAnimationController(vsync: this); if (widget.autoPlay) { _loadAnimation(); } // 添加动画状态监听 _animationController?.addStatusListener((status) { if (status == AnimationStatus.completed && widget.onCompleted != null) { widget.onCompleted!(); } }); } // 加载动画(带缓存) Future _loadAnimation() async { if (widget.onStartLoading != null) { widget.onStartLoading!(); } setState(() { _isLoading = true; _hasError = false; }); try { if (widget.useCache) { final videoItem = _retainedResource == widget.resource && _retainedMovieEntity != null ? _retainedMovieEntity! : await SCGiftVapSvgaManager().acquireSvgaEntity( widget.resource, ); final acquiredNewEntity = !identical(videoItem, _retainedMovieEntity); if (!mounted) { if (acquiredNewEntity) { SCGiftVapSvgaManager().releaseSvgaEntity(videoItem); } return; } setState(() { _releaseRetainedMovieEntity(except: videoItem); _retainedMovieEntity = videoItem; _retainedResource = widget.resource; _animationController?.videoItem = videoItem; _isLoading = false; }); } else { final videoItem = _isNetworkResource ? await SVGAParser.shared.decodeFromURL(widget.resource) : await SVGAParser.shared.decodeFromAssets(widget.resource); if (!mounted) { videoItem.dispose(); return; } setState(() { _animationController?.videoItem = videoItem; _isLoading = false; }); } // 根据循环次数设置播放方式 if (widget.loops == 0) { _animationController?.repeat(); } else { _animationController?.repeat(count: widget.loops); } if (widget.onFinishLoading != null) { widget.onFinishLoading!(); } } catch (e) { if (mounted) { setState(() { _isLoading = false; _hasError = true; }); } if (widget.onError != null) { SCTts.show("fail-${e.toString()}"); widget.onError!(e.toString()); } } } // 播放动画 void play() { if (_animationController?.videoItem != null) { _animationController?.reset(); if (widget.loops == 0) { _animationController?.repeat(); } else { _animationController?.repeat(count: widget.loops); } } else { _loadAnimation(); } } // 暂停动画 void pause() { _animationController?.stop(); } // 停止动画 void stop() { _animationController?.stop(); if (widget.clearsAfterStop) { _animationController?.videoItem = null; _releaseRetainedMovieEntity(); } } // 重新加载动画 void reload() { if (widget.useCache) { _animationController?.videoItem = null; _releaseRetainedMovieEntity(); SCGiftVapSvgaManager().evictSvgaEntity(widget.resource); } _loadAnimation(); } @override void dispose() { stop(); _animationController?.dispose(); _releaseRetainedMovieEntity(); super.dispose(); } void _releaseRetainedMovieEntity({MovieEntity? except}) { final entity = _retainedMovieEntity; if (entity == null || identical(entity, except)) { return; } _retainedMovieEntity = null; _retainedResource = null; SCGiftVapSvgaManager().releaseSvgaEntity(entity); } @override Widget build(BuildContext context) { if (_isLoading && !widget.autoPlay) { return Container( width: widget.width, height: widget.height, child: Center(child: CircularProgressIndicator()), ); } if (_hasError) { return Container(); } return Container( width: widget.width, height: widget.height, child: _animationController != null && _animationController!.videoItem != null ? SVGAImage( _animationController!, fit: BoxFit.fill, clearsAfterStop: widget.clearsAfterStop, ) : Container(), ); } }