Skip to main content
Version: Next

Animations

info

Due to time constraint, we couldn't complete this page. We will complete as soon as possible.

Animations are very important to create a great user experience. Objects in motion have momentum and rarely come to stop immediately. To convey physically believable motion, we need physics based animations. The library provides a way to implement any physically behaving animations.

In the previous article about Animated Values, we learned about useAnimatedValue hook. We also learned how to perform animated transitions by assigning values to a Animated Values. This, however, is not the only way how animations can be implemented. React UI Animate provides a number of ways how animations can be customized and implemented. In this article, we explore different ways to implement animated transitions and how customizations can be done in an animation.

Animated Value Animated Transition

React UI Animate provides one of the easiest way to implement animated transitions with useAnimatedValue hook. We implemented a simple opacity toggle animation by simply assigning and reading opacity node. Let us recall the example from previous article, where we'd update an Animated Value when we cliked a button.

import { AnimatedBlock, useAnimatedValue } from 'react-ui-animate';

export default function () {
const opacity = useAnimatedValue(0); // It initializes opacity object with value 0.

return (
<div>
{/* AnimatedBlock component can read useAnimatedValue() */}
<AnimatedBlock
style={{
opacity: opacity.value, // using opacity with value property
width: 100,
padding: 20,
background: '#39F',
}}
>
ANIMATED
</AnimatedBlock>

{/* Assigning value to 1 auto animates from initialized value 0 to 1 smoothly */}
<button onClick={() => (opacity.value = 1)}>Animate Me</button>
</div>
);
}

In the above example when we click button, opacity is animated from 0 to 1 smoothly. As you can notice AnimatedBlock is used instead of any other HTML Element because the Animated Values cannot be read by HTML Elements, we need special type of Component that can read it. Here, we have AnimatedBlock HOC which is a div element and also can read Animated Values.

In React UI Animate, such Animated Value can accept primitives like number, boolean, string or Animated Value itself. When we initialize a useAnimatedValue, with any primitives, it must be updated / assigned with same primitive type. You also can initiate the useAnimatedValue with conditional operation. For example:

import { useState } from "react";
import { useAnimatedValue } from "react-ui-animate";

export default function () {
const [open, setOpen] = useState(false);
const opacity = useAnimatedValue(open ? 1 : 0); // You can also initialize with a conditional operator

return (
...
);
}

In above example, you could initialize a value with a conditional operator. You dont even need to assign value for update. Changing state open with setOpen can conditionally update the Animated Value with animated transitions.

Strings in Animated Value are also allowed which is benificial for string valued style properties and svg paths. When strings are updated with new string, the useAnimatedValue determines whether it can be interpolated or not. If it can be interpolated, it assigns the animated transitions and if not, it instantly updates to new one. Let us take an example:

import { useAnimatedValue } from "react-ui-animate";

export default function () {
const position = useAnimatedValue("relative"); // assigning strings

return (
...
<button onClick={() => (position.value = "fixed")}>Toggle</button>
);
}

Configuring Animations

Basically, React UI Animate provides two types of animation configurations: Timing and Spring based animations. Timing based animations depends upon duration while Spring based animations are naturally balanced and depends upon properties of an object. By default, Animated Values in React UI Animate implements Spring based animation. useAnimatedValue hook accepts a second optional argument which is an object different animation configurations. To simply modify the nature animation we can use AnimationConfigUtils from reac-ui-animate which has some pre-defined list of animation types.

const opacity = useAnimatedValue(0, { ...AnimationConfigUtils.ELASTIC });

Some other pre-defined animation configs are: EASE, BOUNCE, STIFF, POWER, WOOBLE, etc.

Aditionally, You can also define custom spring configurations by modifying properties: mass, friction and tension

const opacity = useAnimatedValue(0, { mass: 1, friction: 10, tension: 200 });

In the above example, we defined Spring based animations which is naturally balanced. But, In some cases, Timing based animation is needed. The Timing based animations are fully dependent upon durations. We have to define the amount of duration when the animation is finished. The configuration object accepts a duration property where the value is the number of milliseconds the animation should be completed.

const opacity = useAnimatedValue(0, { duration: 1000 });

In the above example, duration is set to 1000 milliseconds i.e. 1 second. When animation value is updated it will complete the animation to in exactly 1 second. These animations are not naturally balanced like Spring based animations because it is linearly interpolated. Linear animations are boring and is not possible in real life. We can define some easing functions to modify the nature of Time based animations. To do so, we should define easing property.

const opacity = useAnimatedValue(0, {
duration: 1000,
easing: Easing.inOut(Easing.ease),
});

In the above example, duration is set to 1000 milliseconds and easing is set to Easing.inOut(Easing.ease) which defines an object moves slowly accelerating to speed and slowly coming to rest. You can find a visualization of some common easing functions at http://easings.net/. Bezier curves also can be implemented.

const opacity = useAnimatedValue(0, {
duration: 1000,
easing: Easing.bezier(0.17, 0.67, 0.83, 0.67),
});

Easing module also has a bezier function which provides a cubic bezier curve, equivalent to CSS Transitions' transition-timing-function. A useful tool to visualize cubic bezier curves can be found at http://cubic-bezier.com/.

Interpolations

Each property can be run through an interpolation first. An interpolation maps input ranges to output ranges, typically using a linear interpolation but also supports easing functions. By default, it will extrapolate the curve beyond the ranges given, but you can also have it clamp the output value. interpolate function allows the Animated Value to map from input ranges to output ranges.

A basic mapping to convert a 0-1 range to a 0-100 range would be:

interpolate(value, [0, 1], [0, 100]);

For example, we want to move an element from left 0px to 500px when the opacity changes from 0 to 1.

import { useAnimatedValue, AnimatedBlock, interpolate } from 'react-ui-animate';

export default function () {
const opacity = useAnimatedValue(0);

return (
<>
<AnimatedBlock
style={{
width: 100,
height: 100,
opacity: opacity.value,
backgroundColor: 'red',
position: 'absolute',
left: interpolate(opacity.value, [0, 1], [0, 500]),
}}
/>

<button onClick={() => (opacity.value = 1)}>Animate Me</button>
</>
);
}

interpolate accepts an animated value as its first argument, array of numbers as its second argument namely input range and array of numbers with same length as second argument namely output range. It also supports multiple range segments as well, which is very much useful for different scenarios like dead zones and other handly tricks.

interpolate(value, [0, 1], ['red', 'black']);

The default behavior of interpolate is that it will extrapolate the curve beyond the ranges given. You can clamp the value output value by passing extrapolation configuration object as 4th argument of interpolate function. You can set the extrapolation by setting the extrapolate, extrapolateLeft, or extrapolateRight options. The default value is extend but you can use clamp to prevent the output value from exceeding outputRange.