Agent skill

custom-plugin-flutter-skill-animations

Production-grade Flutter animations mastery - Implicit and explicit animations, AnimationController, Hero transitions, physics-based motion, Lottie/Rive integration, 60fps optimization with comprehensive code examples

Stars 7
Forks 5

Install this agent skill to your Project

npx add-skill https://github.com/pluginagentmarketplace/custom-plugin-flutter/tree/main/skills/animations

SKILL.md

custom-plugin-flutter: Animations Skill

Quick Start - Production Animation Pattern

dart
class AnimatedProductCard extends StatefulWidget {
  final Product product;
  final bool isSelected;

  const AnimatedProductCard({
    required this.product,
    required this.isSelected,
  });

  @override
  State<AnimatedProductCard> createState() => _AnimatedProductCardState();
}

class _AnimatedProductCardState extends State<AnimatedProductCard>
    with SingleTickerProviderStateMixin {
  late final AnimationController _controller;
  late final Animation<double> _scaleAnimation;
  late final Animation<double> _opacityAnimation;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: const Duration(milliseconds: 200),
      vsync: this,
    );

    _scaleAnimation = Tween<double>(begin: 1.0, end: 0.95).animate(
      CurvedAnimation(parent: _controller, curve: Curves.easeInOut),
    );

    _opacityAnimation = Tween<double>(begin: 1.0, end: 0.8).animate(
      CurvedAnimation(parent: _controller, curve: Curves.easeInOut),
    );
  }

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

  void _onTapDown(TapDownDetails details) => _controller.forward();
  void _onTapUp(TapUpDetails details) => _controller.reverse();
  void _onTapCancel() => _controller.reverse();

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTapDown: _onTapDown,
      onTapUp: _onTapUp,
      onTapCancel: _onTapCancel,
      child: AnimatedBuilder(
        animation: _controller,
        builder: (context, child) {
          return Transform.scale(
            scale: _scaleAnimation.value,
            child: Opacity(
              opacity: _opacityAnimation.value,
              child: child,
            ),
          );
        },
        child: AnimatedContainer(
          duration: const Duration(milliseconds: 300),
          decoration: BoxDecoration(
            border: Border.all(
              color: widget.isSelected ? Colors.blue : Colors.grey,
              width: widget.isSelected ? 2 : 1,
            ),
            borderRadius: BorderRadius.circular(12),
          ),
          child: ProductContent(product: widget.product),
        ),
      ),
    );
  }
}

1. Implicit Animations

Built-in Animated Widgets

dart
// AnimatedContainer - Animate multiple properties
AnimatedContainer(
  duration: Duration(milliseconds: 300),
  curve: Curves.easeInOut,
  width: isExpanded ? 300 : 100,
  height: isExpanded ? 200 : 100,
  decoration: BoxDecoration(
    color: isActive ? Colors.blue : Colors.grey,
    borderRadius: BorderRadius.circular(isExpanded ? 16 : 8),
    boxShadow: isActive ? [BoxShadow(blurRadius: 10)] : [],
  ),
  child: content,
)

// AnimatedOpacity
AnimatedOpacity(
  opacity: isVisible ? 1.0 : 0.0,
  duration: Duration(milliseconds: 200),
  child: content,
)

// AnimatedPositioned (inside Stack)
AnimatedPositioned(
  duration: Duration(milliseconds: 300),
  left: isLeft ? 0 : 100,
  top: isTop ? 0 : 100,
  child: widget,
)

// AnimatedSwitcher - Cross-fade between widgets
AnimatedSwitcher(
  duration: Duration(milliseconds: 300),
  transitionBuilder: (child, animation) {
    return FadeTransition(opacity: animation, child: child);
  },
  child: Text(
    currentText,
    key: ValueKey(currentText), // Important!
  ),
)

// TweenAnimationBuilder - Custom implicit animation
TweenAnimationBuilder<double>(
  tween: Tween(begin: 0, end: progress),
  duration: Duration(milliseconds: 500),
  builder: (context, value, child) {
    return CircularProgressIndicator(value: value);
  },
)

2. Explicit Animations

AnimationController Pattern

dart
class ExplicitAnimationWidget extends StatefulWidget {
  @override
  State<ExplicitAnimationWidget> createState() => _ExplicitAnimationWidgetState();
}

class _ExplicitAnimationWidgetState extends State<ExplicitAnimationWidget>
    with TickerProviderStateMixin {
  late final AnimationController _controller;
  late final Animation<Offset> _slideAnimation;
  late final Animation<double> _fadeAnimation;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: Duration(milliseconds: 500),
      vsync: this,
    );

    _slideAnimation = Tween<Offset>(
      begin: Offset(0, 1),
      end: Offset.zero,
    ).animate(CurvedAnimation(
      parent: _controller,
      curve: Interval(0.0, 0.6, curve: Curves.easeOut),
    ));

    _fadeAnimation = Tween<double>(
      begin: 0,
      end: 1,
    ).animate(CurvedAnimation(
      parent: _controller,
      curve: Interval(0.3, 1.0, curve: Curves.easeIn),
    ));

    _controller.forward();
  }

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

  @override
  Widget build(BuildContext context) {
    return SlideTransition(
      position: _slideAnimation,
      child: FadeTransition(
        opacity: _fadeAnimation,
        child: Content(),
      ),
    );
  }
}

Animation Transitions

dart
// Built-in transitions
FadeTransition(opacity: animation, child: widget)
SlideTransition(position: offsetAnimation, child: widget)
ScaleTransition(scale: animation, child: widget)
RotationTransition(turns: animation, child: widget)
SizeTransition(sizeFactor: animation, child: widget)

// AnimatedBuilder - Custom rendering
AnimatedBuilder(
  animation: _controller,
  builder: (context, child) {
    return Transform(
      transform: Matrix4.identity()
        ..setEntry(3, 2, 0.001)
        ..rotateY(_controller.value * pi),
      alignment: Alignment.center,
      child: child,
    );
  },
  child: Card(),
)

3. Hero Animations

dart
// Source screen
Hero(
  tag: 'product-${product.id}',
  child: Image.network(product.imageUrl),
)

// Destination screen
Hero(
  tag: 'product-${product.id}',
  child: Image.network(product.imageUrl),
)

// Custom Hero flight
Hero(
  tag: 'avatar',
  flightShuttleBuilder: (
    flightContext,
    animation,
    flightDirection,
    fromHeroContext,
    toHeroContext,
  ) {
    return AnimatedBuilder(
      animation: animation,
      builder: (context, _) {
        return CircleAvatar(
          radius: lerpDouble(40, 60, animation.value),
        );
      },
    );
  },
  child: CircleAvatar(),
)

4. Staggered Animations

dart
class StaggeredList extends StatefulWidget {
  @override
  State<StaggeredList> createState() => _StaggeredListState();
}

class _StaggeredListState extends State<StaggeredList>
    with SingleTickerProviderStateMixin {
  late final AnimationController _controller;
  final List<Animation<Offset>> _animations = [];

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: Duration(milliseconds: 1000),
      vsync: this,
    );

    // Create staggered animations
    for (int i = 0; i < 5; i++) {
      final start = i * 0.1;
      final end = start + 0.4;
      _animations.add(
        Tween<Offset>(begin: Offset(1, 0), end: Offset.zero).animate(
          CurvedAnimation(
            parent: _controller,
            curve: Interval(start, end, curve: Curves.easeOut),
          ),
        ),
      );
    }

    _controller.forward();
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: List.generate(5, (index) {
        return SlideTransition(
          position: _animations[index],
          child: ListTile(title: Text('Item $index')),
        );
      }),
    );
  }
}

5. Physics-Based Animations

dart
// Spring simulation
class SpringAnimation extends StatefulWidget {
  @override
  State<SpringAnimation> createState() => _SpringAnimationState();
}

class _SpringAnimationState extends State<SpringAnimation>
    with SingleTickerProviderStateMixin {
  late final AnimationController _controller;
  late Animation<double> _animation;

  final SpringDescription spring = SpringDescription(
    mass: 1,
    stiffness: 100,
    damping: 10,
  );

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(vsync: this);

    final simulation = SpringSimulation(spring, 0, 1, 0);
    _controller.animateWith(simulation);

    _animation = _controller.drive(Tween(begin: 0.0, end: 100.0));
  }

  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: _animation,
      builder: (context, child) {
        return Transform.translate(
          offset: Offset(0, _animation.value),
          child: child,
        );
      },
      child: Ball(),
    );
  }
}

6. Lottie & Rive Integration

dart
// Lottie animation
import 'package:lottie/lottie.dart';

Lottie.asset(
  'assets/loading.json',
  width: 200,
  height: 200,
  fit: BoxFit.contain,
  repeat: true,
  animate: true,
  onLoaded: (composition) {
    _controller.duration = composition.duration;
  },
)

// Rive animation
import 'package:rive/rive.dart';

RiveAnimation.asset(
  'assets/animation.riv',
  fit: BoxFit.cover,
  stateMachines: ['StateMachine1'],
  onInit: (artboard) {
    final controller = StateMachineController.fromArtboard(
      artboard,
      'StateMachine1',
    );
    artboard.addController(controller!);
    _trigger = controller.findInput<bool>('trigger') as SMITrigger;
  },
)

7. Page Transitions

dart
// Custom page route
class FadePageRoute<T> extends PageRouteBuilder<T> {
  final Widget page;

  FadePageRoute({required this.page})
      : super(
          pageBuilder: (context, animation, secondaryAnimation) => page,
          transitionsBuilder: (context, animation, secondaryAnimation, child) {
            return FadeTransition(opacity: animation, child: child);
          },
          transitionDuration: Duration(milliseconds: 300),
        );
}

// Slide + fade combined
transitionsBuilder: (context, animation, secondaryAnimation, child) {
  final offsetAnimation = Tween<Offset>(
    begin: Offset(1.0, 0.0),
    end: Offset.zero,
  ).animate(CurvedAnimation(
    parent: animation,
    curve: Curves.easeInOut,
  ));

  return SlideTransition(
    position: offsetAnimation,
    child: FadeTransition(
      opacity: animation,
      child: child,
    ),
  );
}

8. Performance Optimization

dart
// Use const where possible
const AnimatedContainer(...)

// RepaintBoundary for expensive animations
RepaintBoundary(
  child: AnimatedWidget(),
)

// AnimatedBuilder isolates rebuilds
AnimatedBuilder(
  animation: _controller,
  child: ExpensiveWidget(), // Not rebuilt
  builder: (context, child) {
    return Transform.scale(
      scale: _controller.value,
      child: child, // Reused
    );
  },
)

// Avoid layout-triggering animations
// Good: Transform, Opacity
// Avoid: width/height in tight loops

Troubleshooting Guide

Issue: Animation jank (dropped frames)

1. Use RepaintBoundary to isolate
2. Profile with DevTools Performance
3. Avoid layout changes during animation
4. Use AnimatedBuilder, not setState
5. Check for heavy build methods

Issue: Animation doesn't start

1. Verify AnimationController.forward() called
2. Check vsync: this (TickerProviderStateMixin)
3. Verify widget is mounted before animating
4. Check duration is set

Issue: Animation leaks memory

1. Dispose AnimationController in dispose()
2. Cancel any listeners
3. Use mounted check before setState

Animation Selection Guide

Need Solution
Simple property change AnimatedContainer
Cross-fade widgets AnimatedSwitcher
Custom timing control AnimationController
Shared element Hero
List items appearing Staggered animations
Natural motion Physics simulation
Complex vector Lottie/Rive

Create fluid, 60fps animations in Flutter.

Expand your agent's capabilities with these related and highly-rated skills.

pluginagentmarketplace/custom-plugin-flutter

custom-plugin-flutter-skill-navigation

Production-grade Flutter navigation mastery - Navigator 2.0, GoRouter, deep linking, nested navigation, route guards, web URL handling with comprehensive code examples

7 5
Explore
pluginagentmarketplace/custom-plugin-flutter

custom-plugin-flutter-skill-localization

Production-grade Flutter localization mastery - ARB files, flutter_localizations, intl package, pluralization, RTL support, dynamic locale switching with comprehensive code examples

7 5
Explore
pluginagentmarketplace/custom-plugin-flutter

custom-plugin-flutter-skill-testing

1600+ lines of testing mastery - unit tests, widget tests, integration tests, E2E, coverage, mocking with production-ready code examples.

7 5
Explore
pluginagentmarketplace/custom-plugin-flutter

custom-plugin-flutter-skill-accessibility

Production-grade Flutter accessibility mastery - Semantics API, screen readers (VoiceOver/TalkBack), WCAG 2.1 AA/AAA compliance, inclusive design patterns, automated a11y testing with comprehensive code examples

7 5
Explore
pluginagentmarketplace/custom-plugin-flutter

custom-plugin-flutter-skill-state

2300+ lines of state management mastery - all patterns (Provider, Riverpod, BLoC, GetX), dependency injection, persistence, testing with production-ready code examples.

7 5
Explore
pluginagentmarketplace/custom-plugin-flutter

custom-plugin-flutter-skill-database

1800+ lines of database architecture mastery - SQLite, Hive, ObjectBox, Firestore, encryption, offline-first, sync with production-ready code examples.

7 5
Explore

Didn't find tool you were looking for?

Be as detailed as possible for better results