Skip to main content

๐Ÿ’ซ Custom transitions

๐Ÿ‘ฉ๐Ÿฝโ€How the animations work under the hoodโ€‹

Our library is dependent on the react-native-reanimated (v2) which we use to animate the wrapper around the notification components.

To understand the ins and outs of animations, you can also take a look at the documentation for the aforementioned React Native Reanimated

Our animation system is designed to recognize two kinds of transitions:

  1. transition in
  2. transition out

and it is based on one animated value (shared value) that represents these transitions and animates itself from 0 to 1.

Its range should be self-explanatory, 0 represents the beginning of the transition in animation, whereas 1 stands for the starting point for the transition out kind of animation.

When the notification is about to show up, the value is animated from 0 to 1. When the notification is about to dissapear, it goes from 1 to 0.

Every time a notification is about to be shown, the library renders the UI part wrapped with an <Animated.View /> and applies animated styles to it so it knows how it should animate.

The source of these styles comes from the animation config that is generated with AnimationBuilder class or generateAnimationConfig function and is used internally by the library to generate the animations. You can also use it yourself to create whatever transition you desiere.

Summarizing, there are 4 properties that can controll the transition. They all are handled by AnimationBuilder or generateAnimationConfig and go as follows:

  • animationConfigIn - spring / timing configuration for transition in. REQUIRED
  • animationConfigOut - spring / timing configuration for transition out. Not required, fallbacks to animationConfigIn when not provided
  • transitionInStyles - a worklet function that takes in the animated progress value. It has to return the animated styles. For transition in
  • transitionOutStyles - same as above but for transition out. Not required, fallbacks to ^

The return type of this function (generateAnimationConfig) is CustomAnimationConfig which you can then use when changing the animation types in, e.g., createNotification or notify call.

Generating transition config with AnimationBuilderโ€‹

The AnimationBuilder takes in a config object as a property with which you can define the animation.

Below code snippets should give an idea how it works:

Example 1

export const MoveDown = new AnimationBuilder({
animationConfigIn: {
type: 'timing',
config: {
duration: 400,
},
},
transitionInStyles: (progress) => {
'worklet'
const translateY = interpolate(progress.value, [0, 1], [-100, 0])
return {
opacity: progress.value,
transform: [{ translateY }],
}
},
transitionOutStyles: (progress) => {
'worklet'
const translateY = interpolate(progress.value, [0, 1], [100, 0])
return {
opacity: progress.value,
transform: [{ translateY }],
}
},
})

Example 2

export const RotateIn = generateAnimationConfig({
animationConfigIn: {
type: 'timing',
config: {
duration: 700,
easing: Easing.out(Easing.exp),
},
},
transitionInStyles: (progress) => {
'worklet'

const rotate = interpolate(progress.value, [0, 1], [-360, 0])

return {
transform: [{ rotate: `${rotate}deg` }, { scale: progress.value }],
opacity: progress.value,
}
},
})

Example 3

export const MoveDownRotateIn = MoveDown.add(RotateIn)

Generating transition config with generateAnimationConfigโ€‹

caution

generateAnimation config is deprecated. Please use Animation builder which allows your animations to be more customizable.

The generateAnimationConfig takes in a config object as a property with which you can define the animation.

The code snippets below should give an idea how it works:

Example 1

export const Example1 = generateAnimationConfig({
animationConfigIn: {
type: 'timing',
config: {
duration: 400,
easing: Easing.inOut(Easing.sin),
},
},
transitionInStyles: (progress) => {
'worklet'

const scale = interpolate(progress.value, [0, 1], [0.8, 1])
const translateY = interpolate(progress.value, [0, 1], [-100, 0])

return {
opacity: progress.value,
transform: [{ scale }, { translateY }],
}
},
})

Example 2

export const Example2 = generateAnimationConfig({
animationConfigIn: {
type: 'timing',
config: {
duration: 300,
},
},
animationConfigOut: {
type: 'spring',
config: {
damping: 4,
mass: 0.8,
},
},
transitionInStyles: (progress) => {
'worklet'

const scale = interpolate(progress.value, [0, 1], [0.8, 1])
const translateY = interpolate(progress.value, [0, 1], [-100, 0])

return {
opacity: progress.value,
transform: [{ scale }, { translateY }],
}
},
transitionOutStyles: (progress) => {
'worklet'

const scale = interpolate(progress.value, [0, 1], [0.8, 1])
const translateY = interpolate(progress.value, [0, 1], [100, 0])

return {
opacity: progress.value,
transform: [{ scale }, { translateY }],
}
},
})

As you can see in the above examples, you have full control over the styles and animation configs for both kind of transitions - in and out.

animationConfigIn and animationConfigOutโ€‹

The type ofย animationConfigIn and animationConfigOut:

{
type: "timing" | "spring",
config: WithSpringConfig | WithTimingConfig // -> Reanimated type declarations
}

transitionInStyles and transitionOutStylesโ€‹

The type ofย transitionInStyles and transitionOutStyles is the following function (must be a worklet):

type TransistionStylesConfigFunction = (progress: SharedValue<number>) => AnimatedStylesType