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; final Set _retainedSvgaResources = {}; bool _isLoading = true; bool _hasError = false; @override void initState() { super.initState(); _animationController = SVGAAnimationController(vsync: this); if (widget.autoPlay) { _loadAnimation(); } // 添加动画状态监听 _animationController?.addStatusListener((status) { if (status == AnimationStatus.completed && widget.onCompleted != null) { widget.onCompleted!(); } }); } @override void didUpdateWidget(covariant SVGAHeadwearWidget oldWidget) { super.didUpdateWidget(oldWidget); if (oldWidget.resource != widget.resource || oldWidget.useCache != widget.useCache) { _loadAnimation(); } } // 加载动画(带缓存) Future _loadAnimation() async { if (widget.onStartLoading != null) { widget.onStartLoading!(); } setState(() { _isLoading = true; _hasError = false; }); final resource = widget.resource.trim(); var retainedForLoad = false; try { retainedForLoad = _retainSvgaResourceIfNeeded(resource); final videoItem = await SCGiftVapSvgaManager().loadSvgaEntity( resource, retain: retainedForLoad, ); if (mounted && widget.resource.trim() == resource) { setState(() { _animationController?.videoItem = videoItem; _isLoading = false; }); _releaseRetainedSvgaResourcesExcept(resource); // 根据循环次数设置播放方式 if (widget.loops == 0) { _animationController?.repeat(); } else { _animationController?.repeat(count: widget.loops); } if (widget.onFinishLoading != null) { widget.onFinishLoading!(); } } else if (retainedForLoad) { _releaseSvgaResource(resource); } } catch (e) { if (retainedForLoad) { _releaseSvgaResource(resource); } if (mounted) { setState(() { _isLoading = false; _hasError = true; }); } if (widget.onError != null) { SCTts.show("fail-${e.toString()}"); widget.onError!(e.toString()); } } } bool _retainSvgaResourceIfNeeded(String resource) { if (_retainedSvgaResources.contains(resource)) { return false; } _retainedSvgaResources.add(resource); return true; } void _releaseSvgaResource(String resource, {bool evict = false}) { final shouldRelease = _retainedSvgaResources.remove(resource); if (shouldRelease || evict) { SCGiftVapSvgaManager().removeSvgaEntity(resource, evict: evict); } } void _releaseRetainedSvgaResourcesExcept( String? activeResource, { bool evict = false, }) { final resources = _retainedSvgaResources.toList(growable: false); for (final resource in resources) { if (resource != activeResource) { _releaseSvgaResource(resource, evict: evict); } } } // 播放动画 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) { final resource = widget.resource.trim(); _animationController?.videoItem = null; _releaseSvgaResource(resource, evict: !widget.useCache); } } // 重新加载动画 void reload() { final resource = widget.resource.trim(); _animationController?.stop(); _animationController?.videoItem = null; _releaseSvgaResource(resource, evict: true); _loadAnimation(); } @override void dispose() { _animationController?.stop(); _animationController?.videoItem = null; _releaseRetainedSvgaResourcesExcept(null, evict: !widget.useCache); _animationController?.dispose(); super.dispose(); } @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(), ); } }