在用户从一个屏幕导航到另一个屏幕时,引导他们完成应用通常很有帮助。连接用户浏览应用的常用技术是在一个屏幕到下一个屏幕之间动画化 Widget。这会创建一个连接两个屏幕的视觉锚点。

使用 Hero Widget 将 Widget 从一个屏幕动画到下一个屏幕。本指南使用以下步骤:

  1. 创建两个显示相同图像的屏幕。
  2. 在第一个屏幕上添加 Hero Widget。
  3. 在第二个屏幕上添加 Hero Widget。

1. 创建两个显示相同图像的屏幕

#

在此示例中,在两个屏幕上显示相同的图像。当用户点击图像时,将图像从第一个屏幕动画到第二个屏幕。目前,先创建视觉结构;在后续步骤中处理动画。

dart
import 'package:flutter/material.dart';

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Main Screen')),
      body: GestureDetector(
        onTap: () {
          Navigator.push(
            context,
            MaterialPageRoute<void>(
              builder: (context) {
                return const DetailScreen();
              },
            ),
          );
        },
        child: Image.network('https://picsum.photos/250?image=9'),
      ),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: GestureDetector(
        onTap: () {
          Navigator.pop(context);
        },
        child: Center(
          child: Image.network('https://picsum.photos/250?image=9'),
        ),
      ),
    );
  }
}

2. 在第一个屏幕上添加 Hero Widget

#

要通过动画连接两个屏幕,请将两个屏幕上的 Image Widget 包装在 Hero Widget 中。Hero Widget 需要两个参数:

tag
一个标识 Hero 的对象。它在两个屏幕上必须相同。
child
要在屏幕之间动画的 Widget。
dart
Hero(
  tag: 'imageHero',
  child: Image.network('https://picsum.photos/250?image=9'),
)

3. 在第二个屏幕上添加 Hero Widget

#

为了完成与第一个屏幕的连接,请将第二个屏幕上的 Image 包装在 Hero Widget 中,该 Widget 具有与第一个屏幕中的 Hero 相同的 tag

在将 Hero Widget 应用于第二个屏幕后,屏幕之间的动画就会自动生效。

dart
Hero(
  tag: 'imageHero',
  child: Image.network('https://picsum.photos/250?image=9'),
)

互动示例

#
import 'package:flutter/material.dart';

void main() => runApp(const HeroApp());

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

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(title: 'Transition Demo', home: MainScreen());
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Main Screen')),
      body: GestureDetector(
        onTap: () {
          Navigator.push(
            context,
            MaterialPageRoute<void>(
              builder: (context) {
                return const DetailScreen();
              },
            ),
          );
        },
        child: Hero(
          tag: 'imageHero',
          child: Image.network('https://picsum.photos/250?image=9'),
        ),
      ),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: GestureDetector(
        onTap: () {
          Navigator.pop(context);
        },
        child: Center(
          child: Hero(
            tag: 'imageHero',
            child: Image.network('https://picsum.photos/250?image=9'),
          ),
        ),
      ),
    );
  }
}