[英]Hero animation with an AlertDialog
我想在我的主屏幕上為圖像實現一個英雄動畫,同時在對話框的內容中呈現一個具有相同圖像的AlertDialog小部件。
我希望演示文稿如下面的屏幕截圖所示。 當我點擊左下方的圖像時,我想要英雄動畫和圖像的插圖預覽以及可以點按以消除的透明疊加。
以下代碼不執行英雄動畫。
class AlertDialogTest extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new Material(
child: new InkWell(
child: new Hero(
tag: "preview",
child: new Container(
alignment: FractionalOffset.bottomLeft,
child: new Image(
image: new AssetImage('assets/images/theater.png'),
),
),
),
onTap: () {
showDialog(
context: context,
child: new AlertDialog(
content: new Hero(
tag: "preview",
child: new Image(
image: new AssetImage('assets/images/theater.png'),
),
),
),
);
},
),
);
}
}
Hero過渡僅對兩個PageRoute
實例之間的過渡啟用。 因此,如果您想使用現有的Hero
系統,您應該使用PageRoute
。
您可以嘗試全屏對話框,而不是推送AlertDialog
:
Navigator.push(context, new MaterialPageRoute(
fullscreenDialog: true,
builder: (BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Dialog'),
),
body: new Hero(
tag: "preview",
child: new Image(
image: new AssetImage('assets/images/theater.png'),
),
),
);
}
));
如果您需要半透明屏障,可以擴展PageRoute
並使其更像對話框。
以下是一些實現上述動畫的代碼。
import 'package:flutter/material.dart';
void main() {
runApp(new MaterialApp(
home: new HomePage(),
));
}
class HeroDialogRoute<T> extends PageRoute<T> {
HeroDialogRoute({ this.builder }) : super();
final WidgetBuilder builder;
@override
bool get opaque => false;
@override
bool get barrierDismissible => true;
@override
Duration get transitionDuration => const Duration(milliseconds: 300);
@override
bool get maintainState => true;
@override
Color get barrierColor => Colors.black54;
@override
Widget buildTransitions(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child) {
return new FadeTransition(
opacity: new CurvedAnimation(
parent: animation,
curve: Curves.easeOut
),
child: child
);
}
@override
Widget buildPage(BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation) {
return builder(context);
}
}
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Hero demo'),
),
body: new Align(
alignment: FractionalOffset.center,
child: new Card(
child: new Hero(
tag: 'developer-hero',
child: new Container(
width: 300.0,
height: 300.0,
child: new FlutterLogo(),
),
),
),
),
floatingActionButton: new FloatingActionButton(
child: new Icon(Icons.developer_mode),
onPressed: () {
Navigator.push(
context,
new HeroDialogRoute(
builder: (BuildContext context) {
return new Center(
child: new AlertDialog(
title: new Text('You are my hero.'),
content: new Container(
child: new Hero(
tag: 'developer-hero',
child: new Container(
height: 200.0,
width: 200.0,
child: new FlutterLogo(),
),
),
),
actions: <Widget>[
new FlatButton(
child: new Text('RAD!'),
onPressed: Navigator
.of(context)
.pop,
),
],
),
);
},
),
);
},
),
);
}
}
根據對話框大小和英雄所在的位置,一旦第二個Hero
完成動畫到位,您可能會看到原始Hero
重新出現在對話框下方。 如果這困擾你,你可以堆疊兩個副本的圖像,只有頂部的一個是Hero
,或者你可以觸發動畫隱藏原始的Hero
(可能使用AnimatedCrossFade
),直到對話框關閉。
另一個選擇是您可以自己實現動畫,而不是使用現有的Hero
系統。 您可能想要閱讀動畫文檔,並可能復制heroes.dart的部分內容 。
你可以使用PageRouteBuilder。
用下面的代碼替換你的onTap()代碼
Navigator.of(context).push(
new PageRouteBuilder(
opaque: false,
barrierDismissible:true,
pageBuilder: (BuildContext context, _, __) {
return Container(
new Hero(
tag: "preview",
child: new Image(
image: new AssetImage('assets/images/theater.png'),
),
),
);
}
)
)
在這里演示示例代碼。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.