[flutter] 10秒看懂Hero动画的底层原理

511 阅读1分钟

先看图!(图片7.2MB,网速慢的请耐心等几秒)

iShot_2023-08-06_11.37.34.gif

一句话总结:其实就是一个Overlay在2个页面之间进行“添加并覆盖->执行动画->删除”的过程

全部测试代码:

import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';


class CustomPageRoute<T> extends MaterialPageRoute<T> {
  CustomPageRoute({
    required WidgetBuilder builder,
    RouteSettings? settings,
  }) : super(builder: builder, settings: settings);

  @override
  Duration get transitionDuration => const Duration(milliseconds: 5500);
}

class TestHeroWidget extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        constraints: BoxConstraints.expand(
          height: MediaQuery.of(context).size.height,
        ),
        child: Stack(
          alignment: Alignment.bottomRight,
          children: <Widget>[
            Positioned(
              top: 0,
              left: 0,
              child: InkWell(
                child: Hero(
                    tag: "tag",
                    child: Container(
                      color: Colors.blue,
                      width: 200,
                      height: 200,
                      child: const Image(image: AssetImage("assets/small-image.jpg"),),
                    )),
                onTap: () {
                  Navigator.of(context).push(CustomPageRoute(builder: (_) {
                    return TestHeroTargetWidget();
                  }));
                },
              ),
            ),
            Positioned(
              top: 0,
              left: 0,
              right: 0,
              child: Container(
                alignment: Alignment.centerLeft,
                color: Colors.white,
                child: IconButton(
                  icon: const Icon(Icons.arrow_back_ios),
                  onPressed: () {
                    Navigator.pop(context);
                  },
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

class TestHeroTargetWidget extends StatelessWidget {


  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        constraints: BoxConstraints.expand(
          height: MediaQuery.of(context).size.height,
        ),
        child: Stack(
          alignment: Alignment.bottomRight,
          children: <Widget>[
            InkWell(
              child: Hero(
                  tag: "tag",
                  child: Container(
                    color: Colors.red,
                    width: 500,
                    height: 500,
                    child: const Image(image: AssetImage("assets/large-image.jpg"),),
                  )),
              onTap: () {
                Navigator.of(context).pop();
              },
            ),
            Positioned(
              top: 0,
              left: 0,
              right: 0,
              child: Container(
                alignment: Alignment.centerLeft,
                color: Colors.white,
                child: IconButton(
                  icon: const Icon(Icons.arrow_back_ios),
                  onPressed: () {
                    Navigator.pop(context);
                  },
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}