前面我们介绍的所有路由都是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,其他的都使用过,不懂的可以前往前面的章节了解。最后我们运行一下,就实现如下效果: