萌萌の初音
萌萌の初音
发布于 2021-11-02 / 1294 阅读
0

flutter图片帧动画实现封装

flutter新项目中需要将多张连续图片动画播放出来,对Tween组件进行封装。
直接贴封装好的代码:

import 'package:flutter/material.dart';

class AnimationImageWidget extends StatefulWidget {
  final List<String> _assetList;
  final double? width;
  final double? height;
  bool autoPlay;
  bool loop;
  int interval;

  AnimationImageWidget(this._assetList, {Key? key, this.width, this.height, this.interval = 60, this.autoPlay = true, this.loop = true}) : super(key: key);

  @override
  State<StatefulWidget> createState() {
    return AnimationImageState();
  }
}

class AnimationImageState extends State<AnimationImageWidget> with SingleTickerProviderStateMixin,AutomaticKeepAliveClientMixin<AnimationImageWidget> {
  // 动画控制
  late Animation<double> _animation;
  late AnimationController _controller;
  int interval = 200;

  @override
  void initState() {
    super.initState();

    if (widget.interval != null) {
      interval = widget.interval;
    }
    final int imageLength = widget._assetList.length;
    final int maxTime = interval * imageLength;

    _controller = AnimationController(duration: Duration(milliseconds: maxTime), vsync: this);
    _controller.addStatusListener((AnimationStatus status) {
      if (status == AnimationStatus.completed && widget.loop) {
        _controller.forward(from: 0.0);
      }
    });

    _animation = Tween<double>(begin: 0, end: imageLength.toDouble()).animate(_controller)
      ..addListener(() {
        setState(() {
        });
      });
    if (widget.autoPlay) {
      _controller.forward();
    }
  }

  void startAnimation() => _controller.forward();
  void stopAnimation() => _controller.stop();
  void reStartAnimation(){
    _controller.reset();
    _controller.forward();
  }

  @override
  void didUpdateWidget(AnimationImageWidget oldWidget) {
    if (widget.autoPlay) {
      _controller.forward();
    }
    super.didUpdateWidget(oldWidget);
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  List<Widget> images = [];

  @override
  Widget build(BuildContext context) {
    super.build(context);
    return Container(alignment: AlignmentDirectional.center, child: Image.asset(
      widget._assetList[_animation.value.floor() % widget._assetList.length],
      width: widget.width,
      height: widget.height,
      fit: BoxFit.cover,
      gaplessPlayback: true,///加载下一个动画前保留当前动画防止闪烁
    ));
  }

  @override
  bool get wantKeepAlive => true;
}

使用方法:
AnimationImageWidget(ResDrawable.guide,key: _cotroller1,width: double.infinity,height: double.infinity,interval: 60,autoPlay: true,loop: true)
其中ResDrawable.guide为你图片路径地址的list;
_cotroller为动画控制器,可以进行动画播放、暂停,如:

  GlobalKey<AnimationImageState> _cotroller = GlobalKey<AnimationImageState>();
  _cotroller.currentState?.reStartAnimation();
  _cotroller.currentState?.stopAnimation();

width、height为宽高;
interval为动画间隔;
autoPlay为是否自动播放;
loop为是否循环播放;

使用非常方便,但如果使用TabView和PageView,需要禁用自动播放,用过控制器来进行单独一页播放,否则会引起性能问题。