jpskill.com
🛠️ 開発・MCP コミュニティ

flutter-animations

Comprehensive guide for implementing animations in Flutter. Use when adding motion and visual effects to Flutter apps: implicit animations (AnimatedContainer, AnimatedOpacity, TweenAnimationBuilder), explicit animations (AnimationController, Tween, AnimatedWidget/AnimatedBuilder), hero animations (shared element transitions), staggered animations (sequential/overlapping), and physics-based animations. Includes workflow for choosing the right animation type, implementation patterns, and best practices for performance and user experience.

⚡ おすすめ: コマンド1行でインストール(60秒)

下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。

🍎 Mac / 🐧 Linux
mkdir -p ~/.claude/skills && cd ~/.claude/skills && curl -L -o flutter-animations.zip https://jpskill.com/download/19622.zip && unzip -o flutter-animations.zip && rm flutter-animations.zip
🪟 Windows (PowerShell)
$d = "$env:USERPROFILE\.claude\skills"; ni -Force -ItemType Directory $d | Out-Null; iwr https://jpskill.com/download/19622.zip -OutFile "$d\flutter-animations.zip"; Expand-Archive "$d\flutter-animations.zip" -DestinationPath $d -Force; ri "$d\flutter-animations.zip"

完了後、Claude Code を再起動 → 普通に「動画プロンプト作って」のように話しかけるだけで自動発動します。

💾 手動でダウンロードしたい(コマンドが難しい人向け)
  1. 1. 下の青いボタンを押して flutter-animations.zip をダウンロード
  2. 2. ZIPファイルをダブルクリックで解凍 → flutter-animations フォルダができる
  3. 3. そのフォルダを C:\Users\あなたの名前\.claude\skills\(Win)または ~/.claude/skills/(Mac)へ移動
  4. 4. Claude Code を再起動

⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。

🎯 このSkillでできること

下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。

📦 インストール方法 (3ステップ)

  1. 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
  2. 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
  3. 3. 展開してできたフォルダを、ホームフォルダの .claude/skills/ に置く
    • · macOS / Linux: ~/.claude/skills/
    • · Windows: %USERPROFILE%\.claude\skills\

Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。

詳しい使い方ガイドを見る →
最終更新
2026-05-18
取得日時
2026-05-18
同梱ファイル
11

📖 Skill本文(日本語訳)

※ 原文(英語/中国語)を Gemini で日本語化したものです。Claude 自身は原文を読みます。誤訳がある場合は原文をご確認ください。

Flutterアニメーション

概要

Flutterで、それぞれのユースケースに合った適切なアプローチを用いて、滑らかでパフォーマンスの高いアニメーションを作成します。このスキルでは、暗黙的/明示的なアプローチの選択から、ヒーロー遷移やスタッガードアニメーションのような複雑なエフェクトの実装まで、アニメーションの完全なワークフローをカバーしています。

アニメーションタイプ決定ツリー

要件に基づいて適切なアニメーションタイプを選択してください。

暗黙的アニメーション - 次の場合に使用します。

  • 単一のプロパティ(色、サイズ、位置)をアニメーション化する場合
  • アニメーションが状態変化によってトリガーされる場合
  • 細かい制御が不要な場合

明示的アニメーション - 次の場合に使用します。

  • アニメーションのライフサイクルを完全に制御する必要がある場合
  • 複数のプロパティを同時にアニメーション化する場合
  • アニメーションの状態変化に反応する必要がある場合
  • カスタムアニメーションやトランジションを作成する場合

ヒーローアニメーション - 次の場合に使用します。

  • 2つの画面間で要素を共有する場合
  • 共有要素のトランジションを作成する場合
  • ユーザーが要素がルート間を「飛ぶ」ことを期待する場合

スタッガードアニメーション - 次の場合に使用します。

  • 複数のアニメーションを順次実行したり、重ねて実行したりする場合
  • リップルエフェクトや順次表示を作成する場合
  • リストアイテムを順番にアニメーション化する場合

物理ベースアニメーション - 次の場合に使用します。

  • アニメーションが自然で物理的な感覚であるべき場合
  • バネのような動作、スクロールジェスチャー
  • ドラッグ可能なインタラクション

暗黙的アニメーション

暗黙的アニメーションは、プロパティが変更されたときにアニメーションを自動的に処理します。コントローラーは不要です。

一般的な暗黙的ウィジェット

AnimatedContainer - 複数のプロパティ(サイズ、色、装飾、パディング)をアニメーション化します。

AnimatedContainer(
  duration: const Duration(milliseconds: 300),
  curve: Curves.easeInOut,
  width: _expanded ? 200 : 100,
  height: _expanded ? 200 : 100,
  color: _expanded ? Colors.blue : Colors.red,
  child: const FlutterLogo(),
)

AnimatedOpacity - シンプルなフェードアニメーションです。

AnimatedOpacity(
  opacity: _visible ? 1.0 : 0.0,
  duration: const Duration(milliseconds: 300),
  child: const Text('Hello'),
)

TweenAnimationBuilder - ボイラープレートなしでカスタムトゥイーンアニメーションを作成します。

TweenAnimationBuilder<double>(
  tween: Tween<double>(begin: 0, end: 1),
  duration: const Duration(seconds: 1),
  builder: (context, value, child) {
    return Opacity(
      opacity: value,
      child: Transform.scale(
        scale: value,
        child: child,
      ),
    );
  },
  child: const FlutterLogo(),
)

その他の暗黙的ウィジェット:

  • AnimatedPadding - パディングアニメーション
  • AnimatedPositioned - 位置アニメーション(Stack内)
  • AnimatedAlign - 配置アニメーション
  • AnimatedContainer - 複数のプロパティ
  • AnimatedSwitcher - ウィジェット間のクロスフェード
  • AnimatedDefaultTextStyle - テキストスタイルアニメーション

ベストプラクティス

  • シンプルなケースでは暗黙的アニメーションを優先してください
  • 自然な動きのために適切なカーブを使用してください(Curvesクラスを参照)
  • 予測可能な動作のためにcurvedurationを設定してください
  • 必要に応じてonEndコールバックを使用してください
  • パフォーマンスのためにネストされた暗黙的アニメーションは避けてください

明示的アニメーション

明示的アニメーションは、AnimationControllerを使用して完全な制御を提供します。

コアコンポーネント

AnimationController - アニメーションを駆動します。

late AnimationController _controller;

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

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

Tween - 開始値と終了値の間を補間します。

animation = Tween<double>(begin: 0, end: 300).animate(_controller);

CurvedAnimation - アニメーションにカーブを適用します。

animation = CurvedAnimation(
  parent: _controller,
  curve: Curves.easeInOut,
);

AnimatedWidgetパターン

再利用可能なアニメーションウィジェットに最適です。

class AnimatedLogo extends AnimatedWidget {
  const AnimatedLogo({super.key, required Animation<double> animation})
    : super(listenable: animation);

  @override
  Widget build(BuildContext context) {
    final animation = listenable as Animation<double>;
    return Center(
      child: Container(
        height: animation.value,
        width: animation.value,
        child: const FlutterLogo(),
      ),
    );
  }
}

AnimatedBuilderパターン

アニメーションを伴う複雑なウィジェットに最適です。

class GrowTransition extends StatelessWidget {
  const GrowTransition({
    required this.child,
    required this.animation,
    super.key,
  });

  final Widget child;
  final Animation<double> animation;

  @override
  Widget build(BuildContext context) {
    return Center(
      child: AnimatedBuilder(
        animation: animation,
        builder: (context, child) {
          return SizedBox(
            height: animation.value,
            width: animation.value,
            child: child,
          );
        },
        child: child,
      ),
    );
  }
}

アニメーション状態の監視

animation.addStatusListener((status) {
  switch (status) {
    case AnimationStatus.completed:
      _controller.reverse();
      break;
    case AnimationStatus.dismissed:
      _controller.forward();
      break;
    default:
      break;
  }
});

複数の同時アニメーション

class AnimatedLogo extends AnimatedWidget {
  const AnimatedLogo({super.key, required Animation<double> animation})
    : super(listenable: animation);

  static final _opacityTween = Tween<double>(begin: 0.1, end: 1);
  static final _sizeTween = Tween<double>(begin: 0, end: 300);

  @override
  Widget build(BuildContext context) {
    final animation = listenable as Animation<double>;
    return Center(
      child: Opacity(
        opacity: _opacityTween.evaluate(animation),
        child: Container(
          height: _sizeTween.evaluate(animation),
          width: _sizeTween.evaluate(animation),
          child: const FlutterLogo(),
        ),
      ),
    );
  }
}

組み込みの明示的トランジション

Flutterはすぐに使えるトランジションを提供しています。

  • FadeTransition - フェードアニメーション
  • ScaleTransition - スケールアニメーション
📜 原文 SKILL.md(Claudeが読む英語/中国語)を展開

Flutter Animations

Overview

Create smooth, performant animations in Flutter using the right approach for each use case. This skill covers complete animation workflow: from choosing between implicit/explicit approaches to implementing complex effects like hero transitions and staggered animations.

Animation Type Decision Tree

Choose the right animation type based on your requirements:

Implicit Animations - Use when:

  • Animating a single property (color, size, position)
  • Animation is triggered by state change
  • No need for fine-grained control

Explicit Animations - Use when:

  • Need full control over animation lifecycle
  • Animating multiple properties simultaneously
  • Need to react to animation state changes
  • Creating custom animations or transitions

Hero Animations - Use when:

  • Sharing an element between two screens
  • Creating shared element transitions
  • User expects element to "fly" between routes

Staggered Animations - Use when:

  • Multiple animations should run sequentially or overlap
  • Creating ripple effects or sequential reveals
  • Animating list items in sequence

Physics-Based Animations - Use when:

  • Animations should feel natural/physical
  • Spring-like behavior, scrolling gestures
  • Draggable interactions

Implicit Animations

Implicit animations automatically handle the animation when properties change. No controller needed.

Common Implicit Widgets

AnimatedContainer - Animates multiple properties (size, color, decoration, padding):

AnimatedContainer(
  duration: const Duration(milliseconds: 300),
  curve: Curves.easeInOut,
  width: _expanded ? 200 : 100,
  height: _expanded ? 200 : 100,
  color: _expanded ? Colors.blue : Colors.red,
  child: const FlutterLogo(),
)

AnimatedOpacity - Simple fade animation:

AnimatedOpacity(
  opacity: _visible ? 1.0 : 0.0,
  duration: const Duration(milliseconds: 300),
  child: const Text('Hello'),
)

TweenAnimationBuilder - Custom tween animation without boilerplate:

TweenAnimationBuilder<double>(
  tween: Tween<double>(begin: 0, end: 1),
  duration: const Duration(seconds: 1),
  builder: (context, value, child) {
    return Opacity(
      opacity: value,
      child: Transform.scale(
        scale: value,
        child: child,
      ),
    );
  },
  child: const FlutterLogo(),
)

Other implicit widgets:

  • AnimatedPadding - Padding animation
  • AnimatedPositioned - Position animation (in Stack)
  • AnimatedAlign - Alignment animation
  • AnimatedContainer - Multiple properties
  • AnimatedSwitcher - Cross-fade between widgets
  • AnimatedDefaultTextStyle - Text style animation

Best Practices

  • Prefer implicit animations for simple cases
  • Use appropriate curves for natural motion (see Curves class)
  • Set curve and duration for predictable behavior
  • Use onEnd callback when needed
  • Avoid nested implicit animations for performance

Explicit Animations

Explicit animations provide full control with AnimationController.

Core Components

AnimationController - Drives the animation:

late AnimationController _controller;

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

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

Tween - Interpolates between begin and end values:

animation = Tween<double>(begin: 0, end: 300).animate(_controller);

CurvedAnimation - Applies a curve to the animation:

animation = CurvedAnimation(
  parent: _controller,
  curve: Curves.easeInOut,
);

AnimatedWidget Pattern

Best for reusable animated widgets:

class AnimatedLogo extends AnimatedWidget {
  const AnimatedLogo({super.key, required Animation<double> animation})
    : super(listenable: animation);

  @override
  Widget build(BuildContext context) {
    final animation = listenable as Animation<double>;
    return Center(
      child: Container(
        height: animation.value,
        width: animation.value,
        child: const FlutterLogo(),
      ),
    );
  }
}

AnimatedBuilder Pattern

Best for complex widgets with animations:

class GrowTransition extends StatelessWidget {
  const GrowTransition({
    required this.child,
    required this.animation,
    super.key,
  });

  final Widget child;
  final Animation<double> animation;

  @override
  Widget build(BuildContext context) {
    return Center(
      child: AnimatedBuilder(
        animation: animation,
        builder: (context, child) {
          return SizedBox(
            height: animation.value,
            width: animation.value,
            child: child,
          );
        },
        child: child,
      ),
    );
  }
}

Monitoring Animation State

animation.addStatusListener((status) {
  switch (status) {
    case AnimationStatus.completed:
      _controller.reverse();
      break;
    case AnimationStatus.dismissed:
      _controller.forward();
      break;
    default:
      break;
  }
});

Multiple Simultaneous Animations

class AnimatedLogo extends AnimatedWidget {
  const AnimatedLogo({super.key, required Animation<double> animation})
    : super(listenable: animation);

  static final _opacityTween = Tween<double>(begin: 0.1, end: 1);
  static final _sizeTween = Tween<double>(begin: 0, end: 300);

  @override
  Widget build(BuildContext context) {
    final animation = listenable as Animation<double>;
    return Center(
      child: Opacity(
        opacity: _opacityTween.evaluate(animation),
        child: Container(
          height: _sizeTween.evaluate(animation),
          width: _sizeTween.evaluate(animation),
          child: const FlutterLogo(),
        ),
      ),
    );
  }
}

Built-in Explicit Transitions

Flutter provides ready-to-use transitions:

  • FadeTransition - Fade animation
  • ScaleTransition - Scale animation
  • SlideTransition - Slide animation
  • SizeTransition - Size animation
  • RotationTransition - Rotation animation
  • PositionedTransition - Position animation (in Stack)

Example:

FadeTransition(
  opacity: _animation,
  child: const FlutterLogo(),
)

Performance Tips

  • Dispose controllers when widget is removed
  • Use AnimatedBuilder for optimal rebuilds
  • Avoid setState() in animation listeners (use AnimatedWidget/AnimatedBuilder)
  • Use timeDilation to slow animations during debugging

Hero Animations

Hero animations create shared element transitions between screens.

Basic Hero Animation

Source screen:

Hero(
  tag: 'hero-image',
  child: Image.asset('images/logo.png'),
)

Destination screen:

Hero(
  tag: 'hero-image',  // Same tag!
  child: Image.asset('images/logo.png'),
)

Complete Example

class PhotoHero extends StatelessWidget {
  const PhotoHero({
    super.key,
    required this.photo,
    this.onTap,
    required this.width,
  });

  final String photo;
  final VoidCallback? onTap;
  final double width;

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      width: width,
      child: Hero(
        tag: photo,
        child: Material(
          color: Colors.transparent,
          child: InkWell(
            onTap: onTap,
            child: Image.asset(photo, fit: BoxFit.contain),
          ),
        ),
      ),
    );
  }
}

Navigating between screens:

Navigator.of(context).push(
  MaterialPageRoute<void>(
    builder: (context) {
      return Scaffold(
        appBar: AppBar(title: const Text('Detail')),
        body: Center(
          child: PhotoHero(
            photo: 'images/logo.png',
            width: 300.0,
            onTap: () => Navigator.of(context).pop(),
          ),
        ),
      );
    },
  ),
);

Radial Hero Animation

Transform from circle to rectangle during transition:

class RadialExpansion extends StatelessWidget {
  const RadialExpansion({
    super.key,
    required this.maxRadius,
    this.child,
  }) : clipRectSize = 2.0 * (maxRadius / math.sqrt2);

  final double maxRadius;
  final double clipRectSize;
  final Widget? child;

  @override
  Widget build(BuildContext context) {
    return ClipOval(
      child: Center(
        child: SizedBox(
          width: clipRectSize,
          height: clipRectSize,
          child: ClipRect(child: child),
        ),
      ),
    );
  }
}

Use with MaterialRectCenterArcTween for center-based interpolation:

static RectTween _createRectTween(Rect? begin, Rect? end) {
  return MaterialRectCenterArcTween(begin: begin, end: end);
}

Hero Best Practices

  • Use unique, consistent tags (often the data object itself)
  • Keep hero widget trees similar between routes
  • Wrap images in Material with transparent color for "pop" effect
  • Use timeDilation to debug transitions
  • Consider HeroMode to disable hero animations when needed

Staggered Animations

Run multiple animations with different timing.

Basic Staggered Animation

All animations share one controller:

class StaggerAnimation extends StatelessWidget {
  StaggerAnimation({super.key, required this.controller})
    : opacity = Tween<double>(begin: 0.0, end: 1.0).animate(
        CurvedAnimation(
          parent: controller,
          curve: const Interval(0.0, 0.100, curve: Curves.ease),
        ),
      ),
      width = Tween<double>(begin: 50.0, end: 150.0).animate(
        CurvedAnimation(
          parent: controller,
          curve: const Interval(0.125, 0.250, curve: Curves.ease),
        ),
      );

  final AnimationController controller;
  final Animation<double> opacity;
  final Animation<double> width;

  Widget _buildAnimation(BuildContext context, Widget? child) {
    return Container(
      alignment: Alignment.bottomCenter,
      child: Opacity(
        opacity: opacity.value,
        child: Container(
          width: width.value,
          height: 150,
          color: Colors.blue,
        ),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: controller,
      builder: _buildAnimation,
    );
  }
}

Interval-Based Timing

Each animation has an Interval between 0.0 and 1.0:

animation = Tween<double>(begin: 0, end: 300).animate(
  CurvedAnimation(
    parent: controller,
    curve: const Interval(
      0.25,  // Start at 25% of controller duration
      0.50,  // End at 50% of controller duration
      curve: Curves.ease,
    ),
  ),
);

Common Tweens

borderRadius = BorderRadiusTween(
  begin: BorderRadius.circular(4),
  end: BorderRadius.circular(75),
).animate(
  CurvedAnimation(
    parent: controller,
    curve: const Interval(0.375, 0.500, curve: Curves.ease),
  ),
);

Staggered Menu Animation

class _MenuState extends State<Menu> with SingleTickerProviderStateMixin {
  static const _initialDelayTime = Duration(milliseconds: 50);
  static const _itemSlideTime = Duration(milliseconds: 250);
  static const _staggerTime = Duration(milliseconds: 50);
  static const _buttonDelayTime = Duration(milliseconds: 150);
  static const _buttonTime = Duration(milliseconds: 500);

  final _animationDuration =
      _initialDelayTime +
      (_staggerTime * _menuTitles.length) +
      _buttonDelayTime +
      _buttonTime;

  late AnimationController _controller;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: _animationDuration,
      vsync: this,
    );
    _controller.forward();
  }

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

Stagger Best Practices

  • Use Interval to offset animations in time
  • Ensure controller duration covers all intervals
  • Use curves for natural motion within intervals
  • Consider timeDilation to debug timing
  • Stagger menu items with increasing delay for ripple effect

Physics-Based Animations

Create natural-feeling animations using physics simulations.

Fling Animation

_controller.fling(
  velocity: 2.0,  // Units per second
);

Custom Physics Simulation

_controller.animateWith(
  SpringSimulation(
    spring: const SpringDescription(
      mass: 1,
      stiffness: 100,
      damping: 10,
    ),
    start: 0.0,
    end: 1.0,
    velocity: 0.0,
  ),
);

Common Physics Simulations

  • SpringSimulation - Spring physics
  • BouncingScrollSimulation - Scroll with bounce
  • ClampingScrollSimulation - Scroll without bounce
  • GravitySimulation - Gravity-based

Best Practices

DO

  • Dispose AnimationController in widget disposal
  • Use AnimatedBuilder/AnimatedWidget instead of setState() in listeners
  • Choose appropriate curves for natural motion
  • Use timeDilation for debugging animations
  • Consider performance (avoid heavy widgets in animation builds)
  • Test animations on various devices
  • Support reverse animations for intuitive feel

DON'T

  • Forget to dispose AnimationController (memory leak)
  • Use setState() in animation listeners when AnimatedBuilder suffices
  • Assume animation completes instantly (handle AnimationStatus)
  • Over-animate (animations can distract users)
  • Create animations that feel "jerky" (use smooth curves)
  • Ignore accessibility (respect disableAnimations preference)

Resources

references/

implicit.md - Complete reference for implicit animation widgets with examples and best practices.

explicit.md - Deep dive into explicit animations, AnimationController, and patterns.

hero.md - Hero animations guide with standard and radial transitions.

staggered.md - Staggered animation patterns and timing strategies.

physics.md - Physics-based animations and simulations.

curves.md - Reference for Curves class and choosing appropriate curves.

assets/templates/

Template code for common animation patterns:

  • implicit_animation.dart - Implicit animation examples
  • explicit_animation.dart - Explicit animation setup
  • hero_transition.dart - Hero animation boilerplate
  • staggered_animation.dart - Staggered animation template

同梱ファイル

※ ZIPに含まれるファイル一覧。`SKILL.md` 本体に加え、参考資料・サンプル・スクリプトが入っている場合があります。