Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”.

We often see apps that have an image zoom gradient effect when clicking from the list to the details, rather than a jump to the page. Give users a seamless switching feeling. This effect is often referred to as shared element transition animation, so how is it implemented in Flutter?

In fact, The official Flutter provides us with a very useful control: Hero.

Hero

Hero is a widget that “flies” between routes (pages). Fly hero from one route to another.

The Hero animation code should have the following structure:

1. Define a starting Hero widget, called the “source Hero”. Hero specifies its graphical representation (usually a picture) and identification tag, and is located in the widget tree currently displayed by the source route definition.

2. Define a finished Hero widget called the “target Hero”. The Hero also specifies its graphical representation and the same markup as the source Hero. It is important that both Hero widgets are created using the same tag, usually an object representing the underlying data. For best results, Hero should have nearly the same widget tree.

3. Create a route that contains the target hero. The target route defines the widget tree at the end of the animation.

4. Trigger animation by pushing the destination route onto the stack via navigator. The Navigator push and pop-up actions pair each Hero and trigger the Hero animation with the matching label in the source and destination routes.

5. The Flutter computes the tween that animates the Hero boundary from the start to the end (generates the size and position of each frame) and executes the animation in the overlay.

According to the requirements and definition can be directly stroked code, very simple:

First, the first interface:

Widget build(BuildContext context) { return Scaffold( body: Center( child: Column( mainAxisSize: MainAxisSize.min, children: <Widget>[ InkWell( onTap: (){ Navigator.push(context, MaterialPageRoute(builder: (context) { return SecondHeroPage(tag: "tag",imageUrl: imageUrl,); })); }, child: Hero( tag: "tag", child: Image.network(imageUrl, width: 200, height: 200,)),),),); }Copy the code

Second interface

Widget build(BuildContext context) { return Scaffold( body: Column( children: <Widget>[ InkWell( onTap: (){navigator.of (context).pop();// There are animations after pop}, child: Hero(tag: widget.tag, child: Hero) Image.network(widget.imageurl, width: double. Infinity, height: 500, fit: boxfit.fill,)),),); }Copy the code

HeroMode

The solution to this problem is HeroMode, which can be nested with a Hero component by setting the HeroMode property to Enabled. When the Hero is set to false, the Hero animation will become invalid.

HeroMode(
  enabled: isNeedHero,
  child: Hero(
      tag: "tag",
      child: Image.network(
        imageUrl,
        width: 200,
        height: 200,
      )),
)
Copy the code

Note that the tag must be the same as the tag in the Hero interface

Overall, this effect is very simple to implement, but it would be nice to use it in a real project!

The code address