# Shared element animation

NativeAppWe often encounter such interactions in our daily usage, such as when transitioning from a product list page to a product detail page, where the product images jump between pages, resulting in a smoother transition effect. Another example is the image preview zoom feature in WeChat Moments.InSkylinerendering mode, we call this shared element animation and can be implemented by theshare-elementcomponent.

On a continuousSkylineWhen page transitions, thekeyidenticalshare-elementnodes generate a leap effect, allowing developers to customize the inserted value and the animated curve.Usually acting on pictures, in order to ensure the animation effect, theshare-elementchild node structure should be as consistent as possible.

# Experience Now

Scan the code to open Weixin Mini Program sample, interactive animation - basic components - shared element animation can be experienced.

# How to use it

attribute type Default values Required to fill in Introductions Minimum version
key string yes A map tag, unique within a page 2.29.2
transition-on-gesture boolean false no Does the gesture be animated when it returns? 2.29.2
shuttle-on-push string to no Specifyto pushas the phase transition object. 2.30.2
shuttle-on-pop string to no Specifypopstage leapfrog 2.30.2
rect-tween-type string materialRectArc no Animated Insert Value Curve 2.30.2
on-frame worklet callback no Animation frame callback 2.30.2

Assume thatApage andBpage have correspondingshare-elementcomponents

  1. PushStage: Initiated throughwx.navigateTobyAleading to [[<B,AFor the source page (frompage),BFor the target page (`to [[tag-7-END]] page)
  2. PopStage: Backwx.navigateBackbyB`` A, at this timeBFor the source page (frompage),Afor the destination page (topage)

# Specify a leap object

Developers can specify theshare-elementof a selected source page or target page as a leap.

Since there are two page components involved, the attribute specified by the target pageshare-elementcomponent is used

  1. Push phase: By default, it utilizes the page withBand the share-element with``The component undergoes a significant transformation, and its properties are setshuttle-on-push=fromThis property can be switched toApage.
  2. Pop phase: Default toApageshare-elementcomponent, setting propertiesshuttle-on-pop = fromcan be switched to`B]] page.

Note thaton-framecallbacks are always triggered on theshare-elementcomponent that is designated as a leap object.

# Animation frame callback

A share-element animation is to use the source pageshare-elementThe rectangle whereis located is the starting point and the target pageshare-elementis the endpoint, a process of inserting values, and the animation duration is consistent with page routing time.

enum FlightDirection {
  push = 0,
  pop = 1
}

interface Rect {
  top: number,
  right: number,
  bottom: number,
  left: number,
  width: number,
  height: number
}

interface ShareElementFrameData {
  // 动画进度,0~1
  progress: number,
  // 动画方向,push | pop
  direction: FlightDirection
  // 源页面 share-element 容器尺寸
  begin: Rect,
  // 目标页 share-element 容器尺寸
  end: Rect,
  // 由框架计算的当前帧飞跃物容器尺寸
  current: Rect,
}

type ShareElementOnFrameCallback = (data: ShareElementFrameData) => undefined | Rect

Developers can customize interpolation by usingon-framecallbacks.ShareElementFrameDatacontains the start and end positions, and the frame follows the specified animation curverect-tween-typeand the current progressprogress [[TAG-3END]] calculatedcurrent`location.

The default way to insert the values is to insert theRectofLTWHseparately with the linear values.Whenon-framereturnsundefinedAt this time, the real-time location of the current frame leap is determined bycurrent, and the developer can return theRectobject calculated otherwise to rewrite.

const lerp = (begin: number, end: number, t: number) => {
  'worklet'
  return begin + (end - begin) * t
}

const lerpRect = (begin: Rect, end: Rect, t: number) => {
  'worklet'
  const left = lerp(begin.left, end.left, t);
  const top = lerp(begin.top, end.top, t);
  const width = lerp(begin.width, end.width, t);
  const height = lerp(begin.height, end.height, t);
  const right = left + width
  const bottom = top + height

  return {
    left,
    top,
    right,
    bottom,
    width,
    height
  }
}

# Animated Insert Value Curve

In addition to the way you can customize the insert value, you can also customize the animation curve. The default animation curve is cubic-bezier (0.4, 0.0, 0.2, 1.0) , written asfastOutSlowIn.

When therect-tween-typeis set to the following type, **The default way to insert values is to linearly insertRectofLTWHrespectively.

In addition,rect-tween-typealso supports two special classes of enumeration values for which the animated curve is stillfastOutSlowIn, but the interpolation method is different, the motion trajectory is arc.

  • Materialrectarc: Rectangular Diagonal Animation
  • MaterialRectCenterArc: radial animation

# Working principle

The following example illustrates the various stages of the shared element animation process using the notationpushing.

Note: In fact, theshare-elementnode does not animate itself during animation, but its children move.

# Before the animation begins

The target page is not yet rendered. Create theoverlaylayer above all the pages. The leapfrog will be animated in theOverlaylayer.

# The animation begins at the moment

Callwx.navigateToAnimation fires when pushing a new page,progress = 0The following actions occur at all times

  1. Target page top frame rendering, the frame calculates the targetshare-elementnode position size.
  2. Sourceshare-elementnode off-screen (not displayed).
  3. Move the targetshare-elementnode to theoverlaylayer as a leap object with the same location size as the sourceshare‐elementnodes.

# During the animation process

Depending on the type of insert and the animation curve specified, the targetshare-elementis animated in theoverlaylayer, transitioning from the starting point to the end position.

# The end moment of animation

progress = 1At any moment, move the targetshare-elementfrom theoverlaylayer to the target page to appear in the endpoint position.

# Note

  • Skylineversionshare-elementNo need to be used in conjunction withpage-container
  • Set theshare-elementcomponentpadding,justify-contentand other styles that affect the layout of child nodes will not take effect
  • Can be combined with the page life cycle onRouteDone to do some state recovery at the time of route completion

# Q & A

# Q1: Set the same key, but don't see the leap animation

The shared element animation needs to ensure that theshare-elementnode is created in the first frame of the next page, and the key is set to calculate the target location.

If it is set bysetData, the first frame may be missed.In this case, you can use the Component constructor to construct the next page renders in the first frame as long as it is set (including bysetData) before the componentattachedlifecycle.

# Q2: Children do not follow zoom in / out during the leap

During the animation, the leapfrog container will constantly change its size and position, and if the subnodes want to adapt to follow the change, they need to be defined by percentage rather than write-down to fixed width.

<!-- 由于子 view 固定大小,飞跃过程中仅位置发生变化,大小不变 -->
<share-element key="portrait">
  <view style="width: 50px; height: 50px;"></view>
</share-element>


<!-- 由于子 view 设置跟父节点一样大,飞跃过程中位置、大小均会改变 -->
<share-element key="portrait" style="width: 50px; height: 50px;">
  <view style="width: 100%; height: 100%;"></view>
</share-element>

# Q3: Multiple share-elements are animated together to cover the hierarchical problem

The leapfrog is animated at theoverlay, which is above all the pages.Leapfrogs are traversed in the order in which they are defined in the page component tree (DFS), the further down the hierarchy the higher.

# Q4: When the custom routing gesture returns, the return animation is not seen

The component must first be given thetransition-on-gesture = trueattribute.When the custom routing gesture returns, the shared element animation is triggered only after calling thestartUserGestureinterface.

# Q5: Relationship between shared element animation and routing animation

Shared elements start and end along with page routing animations.If the page entry curve that sets the custom routing is consistent withrect-tween-type, theonFramereturns theprogressvalue as well as [[TAG-1-DAY]]PrimaryAnimation.valueis always consistent.

# Example usage

# Basic usage

Item List Page

<block wx:for="{{list}}" wx:key="id">
  <share-element key="box" transition-on-gesture>
    <image
    src="{{src}}"
    mode="aspectFill"
    />
  </share-element>
</block>

Item Details Page

<share-element key="box" transition-on-gesture>
  <image
  src="{{src}}"
  mode="aspectFit"
  />
</share-element>

Sample Code Snippets - Fundamentals

The effect can be experienced in the developer tools, where it is important to note the effect of the different picturemode.

# Advanced usage

Taking the example of a feature that mimics the image preview and zoom functionality found in WeChat Moments, this explanation discusses how frame callback can be used to address the issue of abrupt transitions caused by differences in image modesmode.The relevant functionality has been encapsulated as aaniamted-imagecomponent, which developers can modify based on.

Here's a brief introduction to the core idea:

  1. Always take thelistpageshare-element
  2. Overlayon-frameoverlay`
  3. Determine the location size of the start and end container based on the actual space occupied by the picture, rather than the space occupied by theshare-elementnode
  4. A thumbnail is used during the leap, and a high-definition image is replaced when downloaded

The default calculation method, which uses the space occupied by theshare-elementnode to determine the start and end position, will produce a jump. Determine the beginning and end position with the actual space occupied by the picture, always using a singlemodeeffect, without jumping. Use the latestnightlytool preview, mobile Android 8.0.33 version. Sample Code Snippets - Advanced