为页面路由过渡设置动画
设计语言(例如 Material)在路由(或屏幕)之间切换时定义了标准行为。但是,有时自定义屏幕之间的过渡可以使应用程序更具特色。为了提供帮助,PageRouteBuilder
提供了一个 Animation
对象。此 Animation
可以与 Tween
和 Curve
对象一起使用来自定义过渡动画。此示例演示了如何通过将新路由从屏幕底部动画到视图中来在路由之间进行过渡。
要创建自定义页面路由过渡,此示例使用以下步骤
- 设置 PageRouteBuilder
- 创建一个
Tween
- 添加一个
AnimatedWidget
- 使用
CurveTween
- 组合两个
Tween
1. 设置 PageRouteBuilder
#首先,使用 PageRouteBuilder
创建一个 Route
。PageRouteBuilder
具有两个回调函数,一个用于构建路由的内容(pageBuilder
),另一个用于构建路由的过渡(transitionsBuilder
)。
以下示例创建了两个路由:一个带有“Go!”按钮的主页路由和一个标题为“页面 2”的第二个路由。
import 'package:flutter/material.dart';
void main() {
runApp(
const MaterialApp(
home: Page1(),
),
);
}
class Page1 extends StatelessWidget {
const Page1({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Center(
child: ElevatedButton(
onPressed: () {
Navigator.of(context).push(_createRoute());
},
child: const Text('Go!'),
),
),
);
}
}
Route _createRoute() {
return PageRouteBuilder(
pageBuilder: (context, animation, secondaryAnimation) => const Page2(),
transitionsBuilder: (context, animation, secondaryAnimation, child) {
return child;
},
);
}
class Page2 extends StatelessWidget {
const Page2({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: const Center(
child: Text('Page 2'),
),
);
}
}
2. 创建 Tween
#为了使新页面从底部动画进入,它应该从 Offset(0,1)
动画到 Offset(0, 0)
(通常使用 Offset.zero
构造函数定义)。在这种情况下,Offset 是 'FractionalTranslation' 小部件的二维向量。将 dy
参数设置为 1 表示页面完整高度的垂直平移。
transitionsBuilder
回调函数有一个 animation
参数。它是一个 Animation<double>
,生成 0 到 1 之间的值。使用 Tween 将 Animation<double>
转换为 Animation<Offset>
transitionsBuilder: (context, animation, secondaryAnimation, child) {
const begin = Offset(0.0, 1.0);
const end = Offset.zero;
final tween = Tween(begin: begin, end: end);
final offsetAnimation = animation.drive(tween);
return child;
},
3. 使用 AnimatedWidget
#Flutter 有一组扩展 AnimatedWidget
的小部件,当动画的值发生变化时,它们会自行重建。例如,SlideTransition 获取一个 Animation<Offset>
,并在动画的值发生变化时平移其子级(使用 FractionalTranslation 小部件)。
AnimatedWidget 返回带有 Animation<Offset>
和子级小部件的 SlideTransition
transitionsBuilder: (context, animation, secondaryAnimation, child) {
const begin = Offset(0.0, 1.0);
const end = Offset.zero;
final tween = Tween(begin: begin, end: end);
final offsetAnimation = animation.drive(tween);
return SlideTransition(
position: offsetAnimation,
child: child,
);
},
4. 使用 CurveTween
#Flutter 提供了一系列缓动曲线,这些曲线会随着时间的推移调整动画的速度。Curves
类提供了一组预定义的常用曲线。例如,Curves.easeOut
使动画开始速度快,结束速度慢。
要使用曲线,请创建一个新的 CurveTween
并向其传递一个曲线
var curve = Curves.ease;
var curveTween = CurveTween(curve: curve);
这个新的 Tween 仍然生成 0 到 1 之间的值。在下一步中,它将与步骤 2 中的 Tween<Offset>
组合。
5. 组合两个 Tween
#要组合这些 tween,请使用 chain()
const begin = Offset(0.0, 1.0);
const end = Offset.zero;
const curve = Curves.ease;
var tween = Tween(begin: begin, end: end).chain(CurveTween(curve: curve));
然后通过将其传递给 animation.drive()
来使用此 tween。这会创建一个新的 Animation<Offset>
,可以将其提供给 SlideTransition
小部件
return SlideTransition(
position: animation.drive(tween),
child: child,
);
这个新的 Tween(或 Animatable)通过首先评估 CurveTween
,然后评估 Tween<Offset>
来生成 Offset
值。当动画运行时,值会按此顺序计算
- 动画(提供给 transitionsBuilder 回调函数)生成 0 到 1 之间的值。
- CurveTween 根据其曲线将这些值映射到 0 到 1 之间的新值。
Tween<Offset>
将double
值映射到Offset
值。
使用 CurvedAnimation
创建具有缓动曲线的 Animation<Offset>
的另一种方法是使用 CurvedAnimation
transitionsBuilder: (context, animation, secondaryAnimation, child) {
const begin = Offset(0.0, 1.0);
const end = Offset.zero;
const curve = Curves.ease;
final tween = Tween(begin: begin, end: end);
final curvedAnimation = CurvedAnimation(
parent: animation,
curve: curve,
);
return SlideTransition(
position: tween.animate(curvedAnimation),
child: child,
);
}
交互式示例
#import 'package:flutter/material.dart';
void main() {
runApp(
const MaterialApp(
home: Page1(),
),
);
}
class Page1 extends StatelessWidget {
const Page1({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Center(
child: ElevatedButton(
onPressed: () {
Navigator.of(context).push(_createRoute());
},
child: const Text('Go!'),
),
),
);
}
}
Route _createRoute() {
return PageRouteBuilder(
pageBuilder: (context, animation, secondaryAnimation) => const Page2(),
transitionsBuilder: (context, animation, secondaryAnimation, child) {
const begin = Offset(0.0, 1.0);
const end = Offset.zero;
const curve = Curves.ease;
var tween = Tween(begin: begin, end: end).chain(CurveTween(curve: curve));
return SlideTransition(
position: animation.drive(tween),
child: child,
);
},
);
}
class Page2 extends StatelessWidget {
const Page2({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: const Center(
child: Text('Page 2'),
),
);
}
}
除非另有说明,否则本网站上的文档反映了 Flutter 的最新稳定版本。页面上次更新于 2024-10-22。 查看源代码 或 报告问题.