skills/flutter/references/features-hero-animations.md

4.6 KiB

name description
features-hero-animations Flutter Hero animations - Hero widget, shared element transitions between routes

Hero Animations

Hero animations create smooth transitions for widgets that move between routes.

Basic Hero

Create a hero animation by wrapping widgets with the same tag.

// First screen
Hero(
  tag: 'avatar',
  child: CircleAvatar(
    radius: 30,
    backgroundImage: NetworkImage('https://example.com/avatar.jpg'),
  ),
)

// Second screen
Hero(
  tag: 'avatar',
  child: CircleAvatar(
    radius: 100,
    backgroundImage: NetworkImage('https://example.com/avatar.jpg'),
  ),
)

Hero Properties

Hero(
  tag: 'unique-tag', // Must be unique and match between screens
  child: Widget(...),
  flightShuttleBuilder: (context, animation, flightDirection, fromHeroContext, toHeroContext) {
    // Custom transition widget
    return ScaleTransition(
      scale: animation,
      child: child,
    );
  },
  placeholderBuilder: (context, size, child) {
    // Widget shown while hero is transitioning
    return Container(
      width: size.width,
      height: size.height,
      color: Colors.grey,
    );
  },
  transitionOnUserGestures: false, // Allow gesture-based transitions
  createRectTween: (begin, end) {
    // Custom tween for hero bounds
    return RectTween(begin: begin, end: end);
  },
)

Complete Example

class FirstScreen extends StatelessWidget {
  const FirstScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('First Screen')),
      body: Center(
        child: GestureDetector(
          onTap: () {
            Navigator.push(
              context,
              MaterialPageRoute(builder: (context) => const SecondScreen()),
            );
          },
          child: Hero(
            tag: 'avatar',
            child: CircleAvatar(
              radius: 50,
              backgroundImage: NetworkImage('https://example.com/avatar.jpg'),
            ),
          ),
        ),
      ),
    );
  }
}

class SecondScreen extends StatelessWidget {
  const SecondScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Second Screen')),
      body: Center(
        child: Hero(
          tag: 'avatar',
          child: CircleAvatar(
            radius: 150,
            backgroundImage: NetworkImage('https://example.com/avatar.jpg'),
          ),
        ),
      ),
    );
  }
}

Custom Flight Shuttle

Customize the hero transition widget.

Hero(
  tag: 'custom-hero',
  flightShuttleBuilder: (context, animation, flightDirection, fromHeroContext, toHeroContext) {
    final hero = flightDirection == HeroFlightDirection.push
        ? toHeroContext.widget
        : fromHeroContext.widget;
    
    return RotationTransition(
      turns: animation,
      child: ScaleTransition(
        scale: animation,
        child: hero,
      ),
    );
  },
  child: Container(...),
)

Multiple Heroes

Use multiple heroes in the same transition.

// First screen
Column(
  children: [
    Hero(
      tag: 'title',
      child: Text('Title', style: TextStyle(fontSize: 24)),
    ),
    Hero(
      tag: 'image',
      child: Image.network('https://example.com/image.jpg'),
    ),
  ],
)

// Second screen
Column(
  children: [
    Hero(
      tag: 'title',
      child: Text('Title', style: TextStyle(fontSize: 48)),
    ),
    Hero(
      tag: 'image',
      child: Image.network('https://example.com/image.jpg'),
    ),
  ],
)

Hero with List

Hero animations work with ListView items.

ListView.builder(
  itemBuilder: (context, index) {
    return ListTile(
      leading: Hero(
        tag: 'avatar-$index',
        child: CircleAvatar(...),
      ),
      title: Text('Item $index'),
      onTap: () {
        Navigator.push(
          context,
          MaterialPageRoute(
            builder: (context) => DetailScreen(index: index),
          ),
        );
      },
    );
  },
)

Key Points

  • Use Hero widget for shared element transitions
  • Tags must be unique and match between screens
  • Hero works automatically with Navigator transitions
  • Use flightShuttleBuilder for custom transition widgets
  • Use placeholderBuilder to show widget during transition
  • Multiple heroes can animate simultaneously
  • Hero animations work with any widget, not just images
  • Ensure hero widgets have similar visual appearance for best effect