import 'dart:async'; import 'package:flutter/material.dart'; import 'dart:ui' as ui; import 'package:flutter/services.dart'; class SpeedControlledGif extends StatefulWidget { final String assetPath; final double speedFactor; final BoxFit? fit; /// [speedFactor] 播放速度倍数,默认1.0, /// 大于1表示加速播放,小于1表示减速播放 const SpeedControlledGif( this.assetPath, { Key? key, this.speedFactor = 1.0, this.fit, }) : super(key: key); @override _SpeedControlledGifState createState() => _SpeedControlledGifState(); } class _SpeedControlledGifState extends State { ui.Codec? _codec; ui.FrameInfo? _currentFrame; Timer? _timer; bool _isDisposed = false; @override void initState() { super.initState(); _loadGif(); } Future _loadGif() async { final data = await rootBundle.load(widget.assetPath); _codec = await ui.instantiateImageCodec(data.buffer.asUint8List()); if (_isDisposed) return; _showNextFrame(); } Future _showNextFrame() async { if (_isDisposed || _codec == null) return; _currentFrame = await _codec!.getNextFrame(); if (_isDisposed) return; if (mounted) { setState(() {}); } // 取当前帧持续时间,单位毫秒 final baseDuration = _currentFrame?.duration.inMilliseconds ?? 100; // 限制最小帧间隔,防止刷新过快 const minFrameDuration = 50; // 计算实际播放帧间隔,speedFactor越大速度越快 final adjustedDuration = (baseDuration / widget.speedFactor) .round() .clamp(minFrameDuration, 10000); _timer = Timer(Duration(milliseconds: adjustedDuration), _showNextFrame); } @override void dispose() { _isDisposed = true; _timer?.cancel(); _codec?.dispose(); super.dispose(); } @override Widget build(BuildContext context) { if (_currentFrame == null) { // 加载中或无帧时显示空容器或占位 return Container(); } return RawImage( image: _currentFrame!.image, fit: widget.fit, ); } }