在Flutter中为go_router设置默认过渡



正如go_router中的文档所描述的,为单个页面设置pageBuilder-转换很容易。但是,我想为所有页面设置默认的PageTransition

如何在Flutter中为go_router设置默认页面转换?

单页:


// this is the proposed method to do it for single pages
// how can i apply it to all pages without writing the same code?
GoRoute(
path: '/login',
builder: (context, state) => const LoginScreen(),
pageBuilder: (context, state) => CustomTransitionPage<void>(
key: state.pageKey,
child: const LoginScreen(),
transitionsBuilder: (context, animation, secondaryAnimation, child) =>
FadeTransition(opacity: animation, child: child),
),
),

向致以最良好的问候

go_router包目前不支持此功能,但为了减少代码重复,您可以创建一个助手函数,为您的路由应用自定义转换,如:

CustomTransitionPage buildPageWithDefaultTransition<T>({
required BuildContext context, 
required GoRouterState state, 
required Widget child,
}) {
return CustomTransitionPage<T>(
key: state.pageKey,
child: child,
transitionsBuilder: (context, animation, secondaryAnimation, child) => 
FadeTransition(opacity: animation, child: child),
);
}
<...>
GoRoute(
path: '/login',
builder: (context, state) => const LoginScreen(),
pageBuilder: (context, state) => buildPageWithDefaultTransition<void>(
context: context, 
state: state, 
child: LoginScreen(),
),
),

更正确的方法是从CustomTransitionPage继承。

class WebPage extends CustomTransitionPage {
WebPage({
LocalKey key,
... // other properties taken from `MaterialPage`
required Widget child
}) : super(
key: key,
transitionBuilder: (...) {
return FadeTransition(...);
}
child: child, // Here you may also wrap this child with some common designed widget
);
}

然后

GoRoute(
path: '/login',
pageBuilder: (context, state) => WebPage(
key: state.pageKey,
child: const LoginScreen(),
),
),

在@mkobuolys答案上进行扩展,可以通过返回创建页面生成器的函数来进一步减少样板,即:

CustomTransitionPage buildPageWithDefaultTransition<T>({
required BuildContext context,
required GoRouterState state,
required Widget child,
}) {
return CustomTransitionPage<T>(
key: state.pageKey,
child: child,
transitionsBuilder: (context, animation, secondaryAnimation, child) =>
FadeTransition(opacity: animation, child: child),
);
}
Page<dynamic> Function(BuildContext, GoRouterState) defaultPageBuilder<T>(
Widget child) =>
(BuildContext context, GoRouterState state) {
return buildPageWithDefaultTransition<T>(
context: context,
state: state,
child: child,
);
};

路由器看起来像:

final _router = GoRouter(
routes: [
GoRoute(
path: '/a',
builder: (context, state) => const PageA(),
pageBuilder: defaultPageBuilder(const PageA()),
),
GoRoute(
path: '/b',
builder: (context, state) => const PageB(),
pageBuilder: defaultPageBuilder(const PageB()),
),
],
);

下面是过渡工厂的代码(主要基于@mkobuolys的答案(。它又增加了3个过渡效果:scalerotationsize

对于我的口味来说,Rotation转弯太多了,size看起来几乎没有过渡效果,但scale有点好。

import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
class RouterTransitionFactory {
static CustomTransitionPage getTransitionPage(
{required BuildContext context,
required GoRouterState state,
required Widget child,
required String type}) {
return CustomTransitionPage(
key: state.pageKey,
child: child,
transitionsBuilder: (context, animation, secondaryAnimation, child) {
switch (type) {
case 'fade':
return FadeTransition(opacity: animation, child: child);
case 'rotation':
return RotationTransition(turns: animation, child: child);
case 'size':
return SizeTransition(sizeFactor: animation, child: child);
case 'scale':
return ScaleTransition(scale: animation, child: child);
default:
return FadeTransition(opacity: animation, child: child);
}
});
}
}

应该这样称呼:

GoRoute(
path: '/settings',
builder: (context, state) => const Settings(), //StatelessWidget
pageBuilder: (context, state) => RouterTransitionFactory.getTransitionPage(
context: context,
state: state,
child: const Settings(), 
type: 'scale', // fade|rotation|scale|size
),
),

为什么不这样使用它比公认的答案更容易

GoRoute defaultTransitionGoRoute({
required String path,
required Widget Function(BuildContext, GoRouterState) pageBuilder,
}) {
return GoRoute(
path: path,
pageBuilder: (context, state) => CustomTransitionPage<void>(
key: state.pageKey,
transitionDuration: const Duration(milliseconds: 300),
child: pageBuilder(context, state),
transitionsBuilder: (context, animation, secondaryAnimation, child) {
return FadeTransition(
opacity: CurveTween(curve: Curves.easeIn).animate(animation),
child: child,
);
},
),
);
}

然后像一样使用

GoRoute(
path: ScreenPaths.favorites,
builder: (context, state) => FavorateScreen(),
),
defaultTransitionGoRoute(
path: ScreenPaths.viewEmail,
pageBuilder: (context, state) {
final extra = state.extra;
return ViewEmailScreen(
email: extra as HiveEmail,
);
},
),

最新更新