分类 explicit · 难度 2/5 · 验证于 Flutter 3.32 / 2026-06
用 PageRouteBuilder 自定义进场动画(淡入 + 轻微上滑),替代默认平台转场。
⏳ 在线预览未就绪:运行 node scripts/sync-gists.mjs 生成 gist 后即可内嵌。
// ✅ 推荐:PageRouteBuilder + CurvedAnimation,淡入 + 上滑,进/出时长都显式设置。
// 可直接粘进 DartPad (https://dartpad.dev) 运行。
import 'package:flutter/material.dart';
void main() => runApp(const _App());
class _App extends StatelessWidget {
const _App();
@override
Widget build(BuildContext context) => const MaterialApp(
debugShowCheckedModeBanner: false,
home: _HomePage(),
);
}
// 可复用的转场:淡入 + 轻微上滑
Route<T> fadeSlideRoute<T>(Widget page) {
return PageRouteBuilder<T>(
transitionDuration: const Duration(milliseconds: 350),
reverseTransitionDuration: const Duration(milliseconds: 300),
pageBuilder: (context, animation, secondaryAnimation) => page,
transitionsBuilder: (context, animation, secondaryAnimation, child) {
final curved = CurvedAnimation(parent: animation, curve: Curves.easeOutCubic);
return FadeTransition(
opacity: curved,
child: SlideTransition(
position: Tween<Offset>(
begin: const Offset(0, 0.08),
end: Offset.zero,
).animate(curved),
child: child, // 复用传入的 child
),
);
},
);
}
class _HomePage extends StatelessWidget {
const _HomePage();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Home')),
body: Center(
child: FilledButton(
onPressed: () => Navigator.of(context).push(fadeSlideRoute(const _SecondPage())),
child: const Text('Open with fade + slide'),
),
),
);
}
}
class _SecondPage extends StatelessWidget {
const _SecondPage();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Second')),
body: const Center(child: Text('Hello 👋')),
);
}
}