带AlertDialog的英雄动画 [英] Hero animation with an AlertDialog
问题描述
我想在主屏幕上为图像实现英雄动画,同时在AlertDialog小部件中显示与对话框内容相同的图像.
I'd like to implement a hero animation for an image on my main screen while presenting an AlertDialog widget with the same image in the dialog's content.
我希望该演示文稿显示在下面的屏幕截图中.当我点击左下角的图像时,我想要英雄动画和图像的嵌入式预览以及可以点击以关闭的透明覆盖层.
I'd like the presentation to appear as in the screenshot below. When I tap the image in the bottom left, I'd like the hero animation and an inset preview of the image along with a transparent overlay that can be tapped to dismiss.
以下代码无法执行英雄动画.
The below code doesn't perform the hero animation.
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'),
),
),
),
);
},
),
);
}
}
推荐答案
仅对PageRoute
的两个实例之间的转换启用了英雄转换.因此,如果要使用现有的Hero
系统,则可能应该使用PageRoute
.
Hero transitions are only enabled for transitions between two instances of PageRoute
. So if you want to make use of the existing Hero
system, you should probably use a PageRoute
.
除了按下AlertDialog
之外,您还可以尝试全屏对话框:
Instead of pushing an AlertDialog
, you could try a full-screen dialog:
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
并使它更像对话框.
If you want a semi-transparent barrier, you can extend PageRoute
and make it a more dialog-like.
以下是实现上述动画的一些代码.
Here is some code that implements the animation above.
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
),直到关闭对话框.
Depending on the dialog size and where your hero is located, you might be able to see the original Hero
reappear underneath the dialog once the second Hero
has finished animating into position. If this bothers you, you could stack two copies the image, with only the top one being a Hero
, or you could trigger an animation to hide the original Hero
(perhaps using AnimatedCrossFade
) until the dialog is closed.
另一个选择是您可以自己实现动画,而不是使用现有的Hero
系统.您可能想阅读动画文档,并可能复制
Another option is that you could implement the animation yourself, instead of using the existing Hero
system. You'd probably want to read up on the animations documentation and possibly copy bits and pieces of heroes.dart.
这篇关于带AlertDialog的英雄动画的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!