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,其他的都使用過,不懂的可以前往前面的章節瞭解。最後我們運行一下,就實現如下效果: