Issue
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'),
),
),
),
);
},
),
);
}
}
Solution
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
.
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'),
),
),
);
}
));
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,
),
],
),
);
},
),
);
},
),
);
}
}
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.
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.
Answered By - Collin Jackson
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.