Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introducing Keyframe-like animation definition schema #2195

Merged
merged 16 commits into from
Jul 20, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Added support for from an to keywords
  • Loading branch information
jmysliv committed Jul 15, 2021
commit 9dd33791156bc4a481d697adb1abe0d2a874309b
4 changes: 2 additions & 2 deletions Example/src/LayoutReanimation/KeyframeAnimation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import Animated, {
export function KeyframeAnimation(): React.ReactElement {
const [show, setShow] = useState(false);
const enteringAnimation = new Keyframe({
0: {
from: {
originX: 50,
transform: [{ rotate: '45deg' }],
},
Expand All @@ -32,7 +32,7 @@ export function KeyframeAnimation(): React.ReactElement {
transform: [{ skewX: '40deg' }],
easing: Easing.exp,
},
100: {
to: {
opacity: 0,
transform: [{ skewX: '-10deg' }],
},
Expand Down
32 changes: 26 additions & 6 deletions docs/docs/api/LayoutAnimations/KeyframeAnimations.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ import { Keyframe } from 'react-native-reanimated';

### 2. Create Keyframe object, define initial and final state

In Keyframe's constructor pass object with definitions of your animation. Object keys should be within range 0-100 and correspond to animation progress,
so to 0 assign the style, you want for your object at the beginning of the animation and to 100 assign the style you want for your object to have at the end of the animation.
In Keyframe's constructor pass object with definitions of your animation. Object keys should be within range `0-100` and correspond to animation progress,
so to `0` assign the style, you want for your object at the beginning of the animation and to `100` assign the style you want for your object to have at the end of the animation.

```js
import { Keyframe } from 'react-native-reanimated';
Expand All @@ -32,10 +32,30 @@ const keyframe = new Keyframe({
}
```

Instead of using '0' and '100', you can define edge points using `from` and `to` keywords. The result will be the same.

```js
import { Keyframe } from 'react-native-reanimated';

const keyframe = new Keyframe({
from: {
transform: [{ rotate: '0deg' }],
},
to: {
transform: [{ rotate: '45deg' }],
},
}
```

Providing keyframe `0` or `from` is required as it contains the initial state of the object you want to animate.
Make sure you provided the initial value for all style properties you want to animate in other keyframes.
Remember not to provide both `0` and `from`, or `100` and `to` keyframe as it will result in parsing conflict.

### 3. Add middle points

Between edge points, you can define middle points in which you want your object to have certain style properties.
Remember that for every keyframe you should provide the same set of style properties!
Remember that you can specify style only for those properties that you set the initial value in `0` or `from` keyframe.
If you won't specify style for some properties, their value will be copied from the previous keyframe.

```js
import { Keyframe } from 'react-native-reanimated';
Expand Down Expand Up @@ -82,17 +102,17 @@ Currently, you can define animations using keyframes only for entry and exit ani
```js
// AnimatedComponent - component created by createAnimatedComponent or imported from Reanimated
// keyframe - Keyframe object
<AnimatedComponent exiting={keyframe} >
<AnimatedComponent exiting={keyframe} />
```
### 2. Customize the animation
```js
<AnimatedComponent exiting={keyframe.duration(3000).delay(200)} >
<AnimatedComponent exiting={keyframe.duration(3000).delay(200)} />
```
### 3. Make sure that your animated component is under an AnimatedLayout. If it's not then add AnimatedLayout somewhere above the component.
```js
<AnimatedLayout> // +
<Text> sth </Text>
<AnimatedComponent exiting={keyframe.duration(3000).delay(200)} >
<AnimatedComponent exiting={keyframe.duration(3000).delay(200)} />
</AnimatedLayout> // +
```

Expand Down
27 changes: 24 additions & 3 deletions src/reanimated2/layoutReanimation/animationBuilder/Keyframe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@ export interface ParsedKeyframesDefinition {
export class Keyframe implements IEntryExitAnimationBuilder {
durationV?: number;
delayV?: number;
definitions: Record<number, KeyframeProps>;
definitions: Record<string, KeyframeProps>;

/*
Keyframe definition should be passed in the constructor as the map
which keys are between range 0 - 100 (%) and correspond to the point in the animation progress.
*/
constructor(definitions: Record<number, KeyframeProps>) {
constructor(definitions: Record<string, KeyframeProps>) {
this.definitions = definitions;
}

Expand All @@ -36,6 +36,27 @@ export class Keyframe implements IEntryExitAnimationBuilder {
value, duration of transition to that value, and optional easing function (defaults to Linear)
*/
const parsedKeyframes: Record<string, KeyframePoint[]> = {};
/*
Parsing keyframes 'from' and 'to'.
*/
if (this.definitions.from) {
if (this.definitions['0']) {
throw Error(
"You cannot provide both keyframe 0 and 'from' as they both specified initial values"
);
}
this.definitions['0'] = this.definitions.from;
delete this.definitions.from;
}
if (this.definitions.to) {
if (this.definitions['100']) {
throw Error(
"You cannot provide both keyframe 100 and 'to' as they both specified values at the end of the animation."
);
}
this.definitions['100'] = this.definitions.to;
delete this.definitions.to;
}
/*
One of the assumptions is that keyframe 0 is required to properly set initial values.
Every other keyframe should contain properties from the set provided as initial values.
Expand Down Expand Up @@ -85,7 +106,7 @@ export class Keyframe implements IEntryExitAnimationBuilder {
}) => {
if (!(key in parsedKeyframes)) {
throw Error(
"Keyframe can contain only that set of properties that were provide as initial values (keyframe 0 or 'from')"
"Keyframe can contain only that set of properties that were provide with initial values (keyframe 0 or 'from')"
);
}
parsedKeyframes[key].push({
Expand Down