import 'package:flutter/material.dart'; import 'package:flutter_animate/flutter_animate.dart'; enum AnimationTrigger { onPageLoad, onActionTrigger, } class AnimationInfo { AnimationInfo({ required this.trigger, required this.effectsBuilder, this.loop = false, this.reverse = false, this.applyInitialState = true, }); final AnimationTrigger trigger; final List Function()? effectsBuilder; final bool applyInitialState; final bool loop; final bool reverse; late AnimationController controller; List? _effects; List get effects => _effects ??= effectsBuilder!(); void maybeUpdateEffects(List? updatedEffects) { if (updatedEffects != null) { _effects = updatedEffects; } } } void createAnimation(AnimationInfo animation, TickerProvider vsync) { final newController = AnimationController(vsync: vsync); animation.controller = newController; } void setupAnimations(Iterable animations, TickerProvider vsync) { for (var animation in animations) { createAnimation(animation, vsync); } } extension AnimatedWidgetExtension on Widget { Widget animateOnPageLoad( AnimationInfo animationInfo, { List? effects, }) { animationInfo.maybeUpdateEffects(effects); return Animate( effects: animationInfo.effects, child: this, onPlay: (controller) => animationInfo.loop ? controller.repeat(reverse: animationInfo.reverse) : null, onComplete: (controller) => !animationInfo.loop && animationInfo.reverse ? controller.reverse() : null, ); } Widget animateOnActionTrigger( AnimationInfo animationInfo, { List? effects, bool hasBeenTriggered = false, }) { animationInfo.maybeUpdateEffects(effects); return hasBeenTriggered || animationInfo.applyInitialState ? Animate( controller: animationInfo.controller, autoPlay: false, effects: animationInfo.effects, child: this) : this; } } class TiltEffect extends Effect { const TiltEffect({ super.delay, super.duration, super.curve, Offset? begin, Offset? end, }) : super( begin: begin ?? const Offset(0.0, 0.0), end: end ?? const Offset(0.0, 0.0), ); @override Widget build( BuildContext context, Widget child, AnimationController controller, EffectEntry entry, ) { Animation animation = buildAnimation(controller, entry); return getOptimizedBuilder( animation: animation, builder: (_, __) => Transform( transform: Matrix4.identity() ..setEntry(3, 2, 0.001) ..rotateX(animation.value.dx) ..rotateY(animation.value.dy), alignment: Alignment.center, child: child, ), ); } }