1.让动画使用起来就像使用widget。
2.可自定义动画。
3.内置平移动画。
演示:
代码:
import 'dart:math';
import 'package:flutter/cupertino.dart';class AnimateView extends StatefulWidget {///子Widgetfinal Widget child;///动画自定义final IAnimate? animate;///是否需要每次刷新时都执行动画final bool isNeedFlashEveryTime;const AnimateView({super.key,required this.child,this.animate,this.isNeedFlashEveryTime = false,});@overrideState<StatefulWidget> createState() => _AnimateViewState();
}class _AnimateViewState extends State<AnimateView>with TickerProviderStateMixin {late IAnimate animate;late AnimationController controller;late Animation animation;@overridevoid initState() {super.initState();animate = widget.animate ??TranslationAnimate(angle: TranslationAnimateDirection.rightToLeft.angle);animate.init();controller = animate.getAnimationController(this);animation = animate.getAnimation(controller, this);//启动动画(正向执行)controller.forward();}@overridevoid didUpdateWidget(covariant AnimateView oldWidget) {super.didUpdateWidget(oldWidget);if (widget.isNeedFlashEveryTime) {animate = widget.animate ??TranslationAnimate(angle: TranslationAnimateDirection.rightToLeft.angle);animate.init();controller = animate.getAnimationController(this);animation = animate.getAnimation(controller, this);//启动动画(正向执行)controller.forward();}}@overrideWidget build(BuildContext context) {return animate.animate(context, widget.child, animation, controller);}
}///动画抽象类。
///实现该类,定制自己的动画。
abstract class IAnimate {///初始化void init();///获取AnimationControllerAnimationController getAnimationController(TickerProvider provider);///获取AnimationAnimation getAnimation(AnimationController controller, State<StatefulWidget> state);///定制自己的动画,每一个item都会调用到animate,///[widget] 执行动画之后的widget///[index] 列表的item的indexWidget animate(BuildContext context,Widget widget,Animation animation,AnimationController controller,);
}///平移动画
class TranslationAnimate extends IAnimate {///动画执行的总长度static double gap = 1000.0;///动画执行角度final int angle;///动画执行时长,毫秒(ms)final int duration;///进入动画还是出去动画final TranslationAnimateType type;///界面的宽,动画需要根据你需要操作的界面宽进行计算,不传代表屏幕宽final double? width;///界面的高,动画需要根据你需要操作的界面高进行计算,不传代表屏幕高final double? height;TranslationAnimate({this.angle = 0,this.duration = 500,this.type = TranslationAnimateType.translateIn,this.width,this.height,});@overrideWidget animate(BuildContext context, Widget widget, Animation animation,AnimationController controller) {final size = MediaQuery.of(context).size;double width = this.width ?? size.width;double height = this.height ?? size.height;double left = 0;double top = 0;///范围0.0->1000.0double animateValue = animation.value;int positiveAngle = angle;if (angle < 0) {int tempAngle = angle % 360;positiveAngle = 360 - tempAngle;}positiveAngle = positiveAngle % 360;///范围0->1double rate = animateValue / gap;if (type == TranslationAnimateType.translateIn) {rate = rate - 1;}if (positiveAngle >= 0 && positiveAngle <= 45 ||positiveAngle >= 135 && positiveAngle <= 225 ||positiveAngle > 315 && positiveAngle <= 360) {///移出距离以宽度为准left = rate * width;if (positiveAngle > 90 && positiveAngle < 270) {left = -left;}double tanValue = tan(positiveAngle * pi / 180);top = rate * width * tanValue;} else if (positiveAngle == 90) {top = rate * height;left = 0;} else if (positiveAngle == 270) {top = -rate * height;left = 0;} else {///移出距离以高度为准top = rate * height;if (positiveAngle > 180 && positiveAngle < 360) {top = -top;}double tanValue = tan(positiveAngle * pi / 180);if (tanValue == 0) {left = 0;} else {left = rate * height / tanValue;}}//print("angle=$positiveAngle");//print("left=$left");//print("top=$top");return Container(transform: Matrix4.translationValues(left, top, 0),child: widget,);}@overrideAnimation getAnimation(AnimationController controller, State<StatefulWidget> state) {return Tween(begin: 0.0, end: gap).animate(controller)..addListener(() {if (state.mounted) {state.setState(() {});}});}@overrideAnimationController getAnimationController(TickerProvider provider) {return AnimationController(duration: Duration(milliseconds: duration), vsync: provider);}@overridevoid init() {}
}///平移动画执行方向枚举
enum TranslationAnimateDirection {///从下往上bottomToTop(90),///从上往下topToBottom(270),///从左往右leftToRight(0),///从右往左rightToLeft(180);///动画执行方向度数final int angle;const TranslationAnimateDirection(this.angle);
}///位移动画类型
enum TranslationAnimateType {///出去动画translateOut,///进入动画translateIn
}