跨頁面切換的動畫 Widget (Hero animations)
在頁面跳轉過程中給使用者加以引導是非常有用的。實現引導的一種通用做法是在頁面切換時為某個元件加上轉場動畫,從而在兩個頁面間建立視覺上的錨定關聯。
在 Flutter 中,可以透過 Hero
widget 實現頁面切換時元件的轉場動畫。
這個教程將包含以下步驟:
-
建立兩個頁面,展示相同的圖片
-
在第一個頁面中加入
Hero
元件 -
在第二個頁面中加入
Hero
元件
1. 建立兩個頁面,展示相同的圖片
在這個範例中,將在兩個頁面中展示相同的圖片。當用戶在第一個頁面點選圖片,會通過一個轉場動畫切換到第二個頁面。現在,我們將會建立頁面的視覺結構,並在後續步驟中處理動畫。
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(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',
),
),
),
);
}
}
Hero
元件
2. 在第一個頁面中加入 為了透過動畫在兩個頁面間建立聯絡,需要把每個頁面的 Image
元件都包裹進 Hero
元件裡面。
Hero
元件有兩個引數:
- `tag`
-
作為 `Hero` 元件的標識,在這兩個頁面中必須相同。
- `child`
-
在兩個螢幕直接跨越的那個 widget。
Hero(
tag: 'imageHero',
child: Image.network(
'https://picsum.photos/250?image=9',
),
)
Hero
元件
3. 在第二個頁面中加入 為了完善與第一個頁面的關聯,同樣需要把第二個頁面中的 Image
元件包裹進 Hero
元件裡面。它的 tag
也必須和第一個頁面相同。
當 Hero
元件被應用到第二個頁面後,頁面的轉場動畫就生效了。
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(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',
),
),
),
),
);
}
}