9.4 Hero动画

Hero很简单,只需要在旧页面和新页面同时使用Hero并配置相同的tag,同一个页面不允许多个tag同时存在。原理就是在路由切换的时候,有一个共享的widget可以在新旧路由之间进行切换,由于共享的 widget在新旧路由的位置和外观有所不同,所以从旧路由逐渐过渡到指定的位置,这就形成了Hero动画。

例子

页面A和页面B,A包含一个矩形图片,在页面顶部,B有一个圆角图片。

在AB跳转的时候,用户头像会逐步过渡到目标的头像上,我肯看下代码:

class BaseHreo extends StatefulWidget {
  final String heroKey;
  BaseHreo({Key key, this.heroKey}) : super(key: key);

  @override
  _BaseHreoState createState() => _BaseHreoState();
}

class _BaseHreoState extends State<BaseHreo> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Hero 动画'),
      ),
      body: _body(),
    );
  }

  Widget _body() {
    return Center(
      child: Column(
        children: <Widget>[
          Hero(
            child: Container(
              width: 100,
              height: 100,
              child: Image.asset('img/2.png'),
            ),
            tag: 'key',
          ),
          OutlineButton(
            child: Text('push'),
            onPressed: () {
              Navigator.push(
                  context,
                  MaterialPageRoute(
                      builder: (ctx) => _BaseHreo(
                            heroKey: 'key',
                          )));
            },
          )
        ],
      ),
    );
  }
}

class _BaseHreo extends StatelessWidget {
  final String heroKey;
  _BaseHreo({Key key, this.heroKey}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('hero 动画'),
      ),
      body: _body(),
    );
  }

  Widget _body() {
    return Align(
      alignment: Alignment.bottomCenter,
      child: Hero(
        child: ClipRRect(
          child: Container(
            width: 300,
            height: 300,
            child: Image.asset(
              'img/2.png',
              fit: BoxFit.fill,
            ),
          ),
          borderRadius: BorderRadius.all(Radius.circular(150)),
        ),
        tag: heroKey ?? 'key',
      ),
    );
  }
}

Hero动画原理很简单,Flutter知道新旧页面共享元素的位置和大小,所以根据两个位置,在动画执行过程中执行插值即可。

results matching ""

    No results matching ""