PageRouteBuilder
前面我们介绍的所有路由都是MaterialPageRoute。但这并不能满足项目中的实际需求,有时候我们也需要修改路由默认的转场效果,这个时候就需要自定义路由,要用到另一个类,它就是PageRouteBuilder,首先我们来看看它的源码:
PageRouteBuilder({ RouteSettings settings, @required this.pageBuilder, this.transitionsBuilder = _defaultTransitionsBuilder, this.transitionDuration = const Duration(milliseconds: 300), this.opaque = true, this.barrierDismissible = false, this.barrierColor, this.barrierLabel, this.maintainState = true, bool fullscreenDialog = false, }) : assert(pageBuilder != null), assert(transitionsBuilder != null), assert(opaque != null), assert(barrierDismissible != null), assert(maintainState != null), assert(fullscreenDialog != null), super(settings: settings, fullscreenDialog: fullscreenDialog);
属性讲解
我们来看一下PageRouteBuilder源码中几个重要的属性,如下图所示:
属性 | 取值 |
Opaque | 是否遮挡整个屏幕 |
transitionsBuilder | 用于自定义的转场效果 |
pageBuilder | 用来创建所要跳转到的页面 |
transitionDuration | 转场动画的持续时间 |
自定义路由转场效果
介绍完几个重要的属性,我们就直接来实战把,这里我们将通过一个自定义的Widget和PageRouteBuild,实现一个简单的Hero效果的路由转场,首先,我们定义一个方法,用于路由的切换,代码如下:
_customToButton(Widget page){ Navigator.of(context).push( PageRouteBuilder<Null>( pageBuilder: (BuildContext context,Animation<double> anim1,Animation<double> anim2){ return AnimatedBuilder( animation: anim1, builder: (BuildContext context,Widget child){ return Opacity( opacity: anim1.value, child: page, ); }, ); }, transitionDuration: Duration(milliseconds: 600) ), ); }
属性上面对应的表格都有,其他属性一眼就能看出来,这里就不在赘述,接着我们需要定义一个通过Hero动画变化的一个CustomLogo自定义图标,代码如下:
class CustomLogo extends StatelessWidget{ final double size; CustomLogo({this.size=200.0}); @override Widget build(BuildContext context) { return Container( color: Colors.blueAccent, width: size, height: size, child: Center( child: FlutterLogo( size: size, ), ), ); } }
然后,我们需要完善主界面的元素,需要Button点击实现路由的跳转,代码如下:
class _MyHomePageState extends State<MyHomePage> { _customToButton(Widget page){ ....代码在上面 } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Center( child: Column( children: <Widget>[ RaisedButton( padding: EdgeInsets.all(10), onPressed: (){ _customToButton(Page2()); }, child: Text( '跳转自定义路由', textAlign: TextAlign.center, style: TextStyle(fontSize: 15), ), ), Hero( tag: 'hero1', child: ClipOval( child: CustomLogo(size: 60,), ), ), Hero( tag: 'hero2', child: Material( color: Colors.transparent, child: Text( '动画', style: TextStyle(fontSize: 15,color: Colors.red), ), ), ), ], ), ), ); } }
前面我们讲过,如果需要实现Hero动画,必须定义源和目标,所以我们跳转的界面也要有一个tag是hero1,代码如下:
class Page2 extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( body: Padding( padding: EdgeInsets.all(30.0), child: Stack( children: <Widget>[ Align( alignment: Alignment.center, child: Hero( tag: "hero1", child: Container( height: 250.0, width: 250.0, child: CustomLogo(), ), ), ), OutlineButton( onPressed: () => Navigator.of(context).pop(), child: Icon(Icons.close), ) ], ), ), ); } }
上面的代码都是前面讲解过的基本元素,除了第一段代码提取出来的方法_customToButton,其他的都使用过,不懂的可以前往前面的章节了解。最后我们运行一下,就实现如下效果: