Skip to content

Commit

Permalink
Callback for layout animation (#2205)
Browse files Browse the repository at this point in the history
In layout animations often many properties are animated at the same time, so there is a need to have a callback that will trigger after all properties finish their animation. This pr adds to LayoutAnimation object optional property callback where user can pass a function that will trigger when layout animation ends.
  • Loading branch information
jmysliv committed Jul 22, 2021
1 parent 0d49278 commit 2e8923e
Show file tree
Hide file tree
Showing 26 changed files with 1,013 additions and 281 deletions.
574 changes: 450 additions & 124 deletions Example/src/LayoutReanimation/DefaultAnimations.tsx

Large diffs are not rendered by default.

9 changes: 8 additions & 1 deletion Example/src/LayoutReanimation/KeyframeAnimation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,14 @@ export function KeyframeAnimation(): React.ReactElement {
transform: [{ rotate: '0deg' }, { scale: 1 }],
easing: Easing.quad,
},
}).duration(2000);
})
.duration(2000)
.withCallback((finished: boolean) => {
'worklet';
if (finished) {
console.log('callback');
}
});
const exitingAnimation = new Keyframe({
0: {
opacity: 1,
Expand Down
12 changes: 12 additions & 0 deletions docs/docs/api/LayoutAnimations/CustomAnimations.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,13 @@ function CustomExitingAnimation(startingValues) {
const initialValues = {
// initial values for animations
};
const callback = (finished: boolean) => {
// optional callback that will fire when layout animation ends
};
return {
initialValues,
animations,
callback,
}
}
```
Expand Down Expand Up @@ -76,9 +80,13 @@ function CustomEnteringAnimation(targetValues) {
const initialValues = {
// initial values for animations
};
const callback = (finished: boolean) => {
// optional callback that will fire when layout animation ends
};
return {
initialValues,
animations,
callback,
}
}
```
Expand Down Expand Up @@ -143,9 +151,13 @@ function CustomLayoutTransition(values) {
const initialValues = {
// initial values for animations
};
const callback = (finished: boolean) => {
// optional callback that will fire when layout animation ends
};
return {
initialValues,
animations,
callback,
}
}
```
Expand Down
10 changes: 10 additions & 0 deletions docs/docs/api/LayoutAnimations/EntryAnimations.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ Simple animation based on changing of opacity.
* `overshootClamping` default: false
* `restDisplacementThreshold` default: 0.001
* `restSpeedThreshold` default: 0.001
* `withCallback` callback that will fire after the entry animation ends

#### Example
<video src="https://user-images.githubusercontent.com/36106620/120317260-b3ccbe00-c2de-11eb-8434-8998b12dfa3c.mov" controls="controls" muted="muted"></video>
Expand All @@ -81,6 +82,7 @@ Animation based on smoothly shaking of component.
#### Modifiers
* `duration` (in ms) default: 250
* `delay` (in ms) default: 0
* `withCallback` callback that will fire after the entry animation ends

#### Example
<video src="https://user-images.githubusercontent.com/36106620/120317341-cc3cd880-c2de-11eb-9d72-4065c740667e.mov" controls="controls" muted="muted"></video>
Expand Down Expand Up @@ -108,6 +110,7 @@ Animation based on smoothly shaking of component.
* `overshootClamping` default: false
* `restDisplacementThreshold` default: 0.001
* `restSpeedThreshold` default: 0.001
* `withCallback` callback that will fire after the entry animation ends

#### Example
<video src="https://user-images.githubusercontent.com/36106620/120317406-deb71200-c2de-11eb-8dee-c658a4e1e47a.mov" controls="controls" muted="muted"></video>
Expand All @@ -131,6 +134,7 @@ Animation based on changing width or height of object.
* `overshootClamping` default: false
* `restDisplacementThreshold` default: 0.001
* `restSpeedThreshold` default: 0.001
* `withCallback` callback that will fire after the entry animation ends

#### Example
<video src="https://user-images.githubusercontent.com/36106620/120317473-f42c3c00-c2de-11eb-8772-b366c2ddde7f.mov" controls="controls" muted="muted"></video>
Expand Down Expand Up @@ -160,6 +164,7 @@ Animation based on changing scale of object.
* `overshootClamping` default: false
* `restDisplacementThreshold` default: 0.001
* `restSpeedThreshold` default: 0.001
* `withCallback` callback that will fire after the entry animation ends

#### Example
<video src="https://user-images.githubusercontent.com/36106620/120317529-04441b80-c2df-11eb-9627-c56e986e44c1.mov" controls="controls" muted="muted"></video>
Expand All @@ -185,6 +190,7 @@ Animation based on horizontal or vertical moving of object.
* `overshootClamping` default: false
* `restDisplacementThreshold` default: 0.001
* `restSpeedThreshold` default: 0.001
* `withCallback` callback that will fire after the entry animation ends

#### Example
<video src="https://user-images.githubusercontent.com/36106620/120317587-1a51dc00-c2df-11eb-937a-c53a237afca2.mov" controls="controls" muted="muted"></video>
Expand All @@ -208,6 +214,7 @@ Animation based on horizontal moving of object with changing of opacity and skew
* `overshootClamping` default: false
* `restDisplacementThreshold` default: 0.001
* `restSpeedThreshold` default: 0.001
* `withCallback` callback that will fire after the entry animation ends

#### Example
<video src="https://user-images.githubusercontent.com/48885911/125057634-c094bc80-e0a9-11eb-98d9-0c8eed1e63b0.mov" controls="controls" muted="muted"></video>
Expand All @@ -230,6 +237,7 @@ Animation based on rotation with scale and opacity change.
* `overshootClamping` default: false
* `restDisplacementThreshold` default: 0.001
* `restSpeedThreshold` default: 0.001
* `withCallback` callback that will fire after the entry animation ends

#### Example
<video src="https://user-images.githubusercontent.com/48885911/125058126-40228b80-e0aa-11eb-8396-7f373af7fcbe.mov" controls="controls" muted="muted"></video>
Expand All @@ -253,6 +261,7 @@ Animation based on horizontal moving of object with rotation.
* `overshootClamping` default: false
* `restDisplacementThreshold` default: 0.001
* `restSpeedThreshold` default: 0.001
* `withCallback` callback that will fire after the entry animation ends

#### Example
<video src="https://user-images.githubusercontent.com/48885911/125058243-60524a80-e0aa-11eb-94c8-79728688e2f3.mov" controls="controls" muted="muted"></video>
Expand All @@ -278,6 +287,7 @@ Animation based on rotation of object.
* `overshootClamping` default: false
* `restDisplacementThreshold` default: 0.001
* `restSpeedThreshold` default: 0.001
* `withCallback` callback that will fire after the entry animation ends

#### Example
<video src="https://user-images.githubusercontent.com/48885911/125058359-79f39200-e0aa-11eb-8c78-c31e461e3748.mov" controls="controls" muted="muted"></video>
11 changes: 10 additions & 1 deletion docs/docs/api/LayoutAnimations/ExitAnimations.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ Simple animation based on changing of opacity.
* `overshootClamping` default: false
* `restDisplacementThreshold` default: 0.001
* `restSpeedThreshold` default: 0.001
* `withCallback` callback that will fire after the exit animation ends

#### Example
<video src="https://user-images.githubusercontent.com/36106620/120317304-c1824380-c2de-11eb-8aed-4c83cfe2f2cc.mov" controls="controls" muted="muted"></video>
Expand All @@ -81,6 +82,7 @@ Animation based on smoothly shaking of component.
#### Modifiers
* `duration` (in ms) default: 250
* `delay` (in ms) default: 0
* `withCallback` callback that will fire after the exit animation ends

#### Example
<video src="https://user-images.githubusercontent.com/36106620/120317374-d52daa00-c2de-11eb-9fc5-320dfaf50440.mov" controls="controls" muted="muted"></video>
Expand Down Expand Up @@ -108,6 +110,7 @@ Animation based on smoothly shaking of component.
* `overshootClamping` default: false
* `restDisplacementThreshold` default: 0.001
* `restSpeedThreshold` default: 0.001
* `withCallback` callback that will fire after the exit animation ends

#### Example
<video src="https://user-images.githubusercontent.com/36106620/120317439-e971a700-c2de-11eb-89d7-1a934922b7fd.mov" controls="controls" muted="muted"></video>
Expand All @@ -131,6 +134,7 @@ Animation based on changing width or height of object.
* `overshootClamping` default: false
* `restDisplacementThreshold` default: 0.001
* `restSpeedThreshold` default: 0.001
* `withCallback` callback that will fire after the exit animation ends

#### Example
<video src="https://user-images.githubusercontent.com/36106620/120317500-fbebe080-c2de-11eb-9901-693aa4ad0ba0.mov" controls="controls" muted="muted"></video>
Expand Down Expand Up @@ -160,7 +164,7 @@ Animation based on changing scale of object.
* `overshootClamping` default: false
* `restDisplacementThreshold` default: 0.001
* `restSpeedThreshold` default: 0.001

* `withCallback` callback that will fire after the exit animation ends
#### Example
<video src="https://user-images.githubusercontent.com/36106620/120317554-0efeb080-c2df-11eb-88cf-6ec47778dccb.mov" controls="controls" muted="muted"></video>

Expand All @@ -185,6 +189,7 @@ Animation based on horizontal or vertical moving of object.
* `overshootClamping` default: false
* `restDisplacementThreshold` default: 0.001
* `restSpeedThreshold` default: 0.001
* `withCallback` callback that will fire after the exit animation ends

#### Example
<video src="https://user-images.githubusercontent.com/36106620/120317603-22118080-c2df-11eb-9083-b5ba3f043dbc.mov" controls="controls" muted="muted"></video>
Expand All @@ -208,6 +213,7 @@ Animation based on horizontal moving of object with changing of opacity and skew
* `overshootClamping` default: false
* `restDisplacementThreshold` default: 0.001
* `restSpeedThreshold` default: 0.001
* `withCallback` callback that will fire after the exit animation ends

#### Example
<video src="https://user-images.githubusercontent.com/48885911/125058070-2e40e880-e0aa-11eb-98eb-326a34f23f39.mov" controls="controls" muted="muted"></video>
Expand All @@ -230,6 +236,7 @@ Animation based on rotation with scale and opacity change.
* `overshootClamping` default: false
* `restDisplacementThreshold` default: 0.001
* `restSpeedThreshold` default: 0.001
* `withCallback` callback that will fire after the exit animation ends

#### Example
<video src="https://user-images.githubusercontent.com/48885911/125058201-57617900-e0aa-11eb-951f-46ac27787d3e.mov" controls="controls" muted="muted"></video>
Expand All @@ -253,6 +260,7 @@ Animation based on horizontal moving of object with rotation.
* `overshootClamping` default: false
* `restDisplacementThreshold` default: 0.001
* `restSpeedThreshold` default: 0.001
* `withCallback` callback that will fire after the exit animation ends

#### Example
<video src="https://user-images.githubusercontent.com/48885911/125058307-6e07d000-e0aa-11eb-8379-4536c0806aee.mov" controls="controls" muted="muted"></video>
Expand All @@ -278,6 +286,7 @@ Animation based on rotation of object.
* `overshootClamping` default: false
* `restDisplacementThreshold` default: 0.001
* `restSpeedThreshold` default: 0.001
* `withCallback` callback that will fire after the exit animation ends

#### Example
<video src="https://user-images.githubusercontent.com/48885911/125058418-8841ae00-e0aa-11eb-9ac1-39df437512c4.mov" controls="controls" muted="muted"></video>
2 changes: 2 additions & 0 deletions docs/docs/api/LayoutAnimations/KeyframeAnimations.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,8 @@ How long the animation should last.
default: 0
Allows to start with a specified delay.
### withCallback
Allows to execute code when keyframe animation ends.
## Example
```js
Expand Down
3 changes: 3 additions & 0 deletions docs/docs/api/LayoutAnimations/LayoutTransitions.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ Worklet that drives the easing curve for the animation
default: 0
Allows to start with a specified delay.

### withCallback
Allows to execute code when keyframe animation ends

## Example

<video src="https://user-images.githubusercontent.com/36106620/120326673-44100080-c2e9-11eb-8b14-564d3b4e3102.mov" controls="controls" muted="muted"></video>
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@
"babel-eslint": "^10.0.3",
"babel-jest": "^26.6.3",
"babel-plugin-module-resolver": "^4.1.0",
"eslint": "^6.5.1",
"eslint": "^7.31.0",
"eslint-config-prettier": "^6.4.0",
"eslint-config-standard": "^14.1.0",
"eslint-import-resolver-babel-module": "^5.2.0",
Expand Down
5 changes: 5 additions & 0 deletions react-native-reanimated.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -650,6 +650,7 @@ declare module 'react-native-reanimated' {
constructor(definitions: Map<number, KeyframeProps[]>);
duration(durationMs: number): Keyframe;
delay(delayMs: number): Keyframe;
withCallback(callback: (finished: boolean) => void);
}
export class BaseAnimationBuilder {
static duration(durationMs: number): BaseAnimationBuilder;
Expand All @@ -672,6 +673,8 @@ declare module 'react-native-reanimated' {
restDisplacementThreshold(restDisplacementThresholdFactor: number): BaseAnimationBuilder;
static restSpeedThreshold(restSpeedThresholdFactor: number): BaseAnimationBuilder;
restSpeedThreshold(restSpeedThresholdFactor: number): BaseAnimationBuilder;
static withCallback(callback: (finished: boolean) => void): BaseAnimationBuilder;
withCallback(callback: (finished: boolean) => void): BaseAnimationBuilder;
}

export class Layout extends BaseAnimationBuilder {};
Expand All @@ -686,6 +689,8 @@ declare module 'react-native-reanimated' {
duration(durationMs: number): BounceAnimationBuilder;
static delay(durationMs: number): BounceAnimationBuilder;
delay(durationMs: number): BounceAnimationBuilder;
static withCallback(callback: (finished: boolean) => void): BaseBounceAnimationBuilder;
withCallback(callback: (finished: boolean) => void): BaseBounceAnimationBuilder;
};

export interface AnimatedLayout extends React.Component {};
Expand Down
4 changes: 3 additions & 1 deletion src/reanimated2/layoutReanimation/AnimatedRoot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ runOnUI(() => {
if (typeof configs[tag][type] !== 'function') {
console.error(`${type} animation for a tag: ${tag} it not a function!`);
}

const style = configs[tag][type](yogaValues);
const sv: { value: boolean; _value: boolean } = configs[tag].sv;
_stopObservingProgress(tag, false);
Expand All @@ -55,6 +54,9 @@ runOnUI(() => {
if (finished) {
_stopObservingProgress(tag, finished);
}
if (style.callback) {
style.callback(finished);
}
};
configs[tag].sv.value = animation;
_startObservingProgress(tag, sv);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@ import {
EntryExitAnimationFunction,
AnimationFunction,
BaseBuilderAnimationConfig,
LayoutAnimationAndConfig,
EntryExitAnimationBuild,
LayoutAnimationAndConfig,
} from './commonTypes';
import { EasingFn } from '../../Easing';

export class BaseAnimationBuilder {
durationV?: number;
easingV?: EasingFn;
Expand All @@ -20,6 +19,7 @@ export class BaseAnimationBuilder {
overshootClampingV?: number;
restDisplacementThresholdV?: number;
restSpeedThresholdV?: number;
callbackV?: (finished: boolean) => void;

static createInstance: () => BaseAnimationBuilder;
build: EntryExitAnimationBuild = () => {
Expand Down Expand Up @@ -140,6 +140,18 @@ export class BaseAnimationBuilder {
return this;
}

static withCallback(
callback: (finished: boolean) => void
): BaseAnimationBuilder {
const instance = this.createInstance();
return instance.withCallback(callback);
}

withCallback(callback: (finsihed: boolean) => void): BaseAnimationBuilder {
this.callbackV = callback;
return this;
}

static build(): EntryExitAnimationFunction {
const instance = this.createInstance();
return instance.build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
export class BaseBounceAnimationBuilder {
durationV?: number;
delayV?: number;
callbackV?: (finished: boolean) => void;

static createInstance: () => BaseBounceAnimationBuilder;
build: EntryExitAnimationBuild = () => {
Expand All @@ -36,6 +37,20 @@ export class BaseBounceAnimationBuilder {
return this;
}

static withCallback(
callback: (finished: boolean) => void
): BaseBounceAnimationBuilder {
const instance = this.createInstance();
return instance.withCallback(callback);
}

withCallback(
callback: (finsihed: boolean) => void
): BaseBounceAnimationBuilder {
this.callbackV = callback;
return this;
}

getDelayFunction(): AnimationFunction {
const delay = this.delayV;
return delay
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export interface ParsedKeyframesDefinition {
export class Keyframe implements IEntryExitAnimationBuilder {
durationV?: number;
delayV?: number;
callbackV?: (finished: boolean) => void;
definitions: Record<string, KeyframeProps>;

/*
Expand Down Expand Up @@ -173,6 +174,11 @@ export class Keyframe implements IEntryExitAnimationBuilder {
return this;
}

withCallback(callback: (finsihed: boolean) => void): Keyframe {
this.callbackV = callback;
return this;
}

private getDelayFunction(): AnimationFunction {
const delay = this.delayV;
return delay
Expand All @@ -187,6 +193,7 @@ export class Keyframe implements IEntryExitAnimationBuilder {
const delay = this.delayV;
const delayFunction = this.getDelayFunction();
const { keyframes, initialValues } = this.parseDefinitions();
const callback = this.callbackV;

return (_targetValues) => {
'worklet';
Expand Down Expand Up @@ -248,6 +255,7 @@ export class Keyframe implements IEntryExitAnimationBuilder {
return {
animations: animations,
initialValues: initialValues,
callback: callback,
};
};
};
Expand Down

0 comments on commit 2e8923e

Please sign in to comment.