带AlertDialog的英雄动画 [英] Hero animation with an AlertDialog

查看:91
本文介绍了带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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆