Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Implement Flutter animations: implicit, explicit, hero, staggered, and physics-based with a decision tree guide.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
assets/templates/hero_transition.dart
1import 'package:flutter/material.dart';23/// Hero animation example for shared element transitions4///5/// This example demonstrates:6/// - Basic hero animation with matching tags7/// - Custom PhotoHero widget8/// - Navigation between screens with hero transition9/// - MaterialRectCenterArcTween for aspect ratio preservation1011void main() => runApp(const HeroAnimationApp());1213class HeroAnimationApp extends StatelessWidget {14const HeroAnimationApp({super.key});1516@override17Widget build(BuildContext context) {18return MaterialApp(19title: 'Hero Animation',20theme: ThemeData(21colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),22),23home: const GalleryScreen(),24);25}26}2728/// Custom hero widget for images29class PhotoHero extends StatelessWidget {30const PhotoHero({31super.key,32required this.photo,33this.onTap,34required this.width,35});3637final String photo;38final VoidCallback? onTap;39final double width;4041@override42Widget build(BuildContext context) {43return SizedBox(44width: width,45child: Hero(46tag: photo,47child: Material(48color: Colors.transparent,49child: InkWell(50onTap: onTap,51child: Image.asset(52photo,53fit: BoxFit.contain,54errorBuilder: (context, error, stackTrace) {55return Container(56width: width,57height: width,58color: Colors.grey,59child: const Icon(Icons.broken_image),60);61},62),63),64),65),66);67}68}6970/// Gallery screen showing multiple hero images71class GalleryScreen extends StatelessWidget {72const GalleryScreen({super.key});7374static const List<String> _photos = [75'images/photo1.png',76'images/photo2.png',77'images/photo3.png',78];7980@override81Widget build(BuildContext context) {82return Scaffold(83appBar: AppBar(title: const Text('Hero Gallery')),84body: GridView.builder(85gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(86crossAxisCount: 2,87),88itemCount: _photos.length,89itemBuilder: (context, index) {90return Padding(91padding: const EdgeInsets.all(8.0),92child: PhotoHero(93photo: _photos[index],94width: 100,95onTap: () {96Navigator.of(context).push(97MaterialPageRoute<void>(98builder: (context) => DetailScreen(photo: _photos[index]),99),100);101},102),103);104},105),106);107}108}109110/// Detail screen showing hero image in fullscreen111class DetailScreen extends StatelessWidget {112const DetailScreen({super.key, required this.photo});113114final String photo;115116@override117Widget build(BuildContext context) {118return Scaffold(119appBar: AppBar(title: const Text('Detail')),120body: Center(121child: PhotoHero(122photo: photo,123width: MediaQuery.of(context).size.width - 32,124onTap: () => Navigator.of(context).pop(),125),126),127);128}129}130131/// Example with circular hero (using placeholder instead of asset)132class CircularHeroExample extends StatefulWidget {133const CircularHeroExample({super.key});134135@override136State<CircularHeroExample> createState() => _CircularHeroExampleState();137}138139class _CircularHeroExampleState extends State<CircularHeroExample> {140@override141Widget build(BuildContext context) {142return Scaffold(143appBar: AppBar(title: const Text('Circular Hero')),144body: ListView(145children: List.generate(3, (index) {146final tag = 'circle-$index';147return Center(148child: Padding(149padding: const EdgeInsets.all(16.0),150child: Hero(151tag: tag,152child: Material(153color: Colors.transparent,154child: InkWell(155onTap: () {156Navigator.of(context).push(157MaterialPageRoute<void>(158builder: (context) =>159CircularDetailScreen(tag: tag, index: index),160),161);162},163child: Container(164width: 80,165height: 80,166decoration: const BoxDecoration(167color: Colors.blue,168shape: BoxShape.circle,169),170),171),172),173),174),175);176}),177),178);179}180}181182class CircularDetailScreen extends StatelessWidget {183const CircularDetailScreen({184super.key,185required this.tag,186required this.index,187});188189final String tag;190final int index;191192@override193Widget build(BuildContext context) {194return Scaffold(195appBar: AppBar(title: const Text('Circular Detail')),196body: Center(197child: Hero(198tag: tag,199child: Material(200color: Colors.transparent,201child: InkWell(202onTap: () => Navigator.of(context).pop(),203child: Container(204width: 300,205height: 300,206decoration: BoxDecoration(207color: Colors.blue.withValues(alpha: 0.8),208borderRadius: BorderRadius.circular(150),209),210child: Center(211child: Text(212'Image $index',213style: const TextStyle(color: Colors.white, fontSize: 24),214),215),216),217),218),219),220),221);222}223}224