chatapp3-flutter/lib/ui_kit/widgets/headdress/headdress_widget.dart
2026-04-09 21:32:23 +08:00

208 lines
5.1 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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<SVGAHeadwearWidget>
with SingleTickerProviderStateMixin {
SVGAAnimationController? _animationController;
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<void> _loadAnimation() async {
if (widget.onStartLoading != null) {
widget.onStartLoading!();
}
setState(() {
_isLoading = true;
_hasError = false;
});
try {
// 检查缓存
MovieEntity? videoItem;
if (widget.useCache) {
videoItem = SCGiftVapSvgaManager().videoItemCache[widget.resource];
}
// 如果没有缓存,则进行解析
if (videoItem == null) {
videoItem =
_isNetworkResource
? await SVGAParser.shared.decodeFromURL(widget.resource)
: await SVGAParser.shared.decodeFromAssets(widget.resource);
videoItem.autorelease =false;
// 存入缓存
if (widget.useCache) {
SCGiftVapSvgaManager().videoItemCache[widget.resource] = videoItem;
}
}
if (mounted) {
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;
}
}
// 重新加载动画
void reload() {
if (widget.useCache) {
// 清除缓存项
SCGiftVapSvgaManager().videoItemCache.remove(widget.resource);
}
_loadAnimation();
}
@override
void dispose() {
stop();
_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(),
);
}
}