1.6.0-beta63 • Published 2 years ago

@huds0n/animations v1.6.0-beta63

Weekly downloads
183
License
MIT
Repository
-
Last release
2 years ago

Status GitHub Issues GitHub Pull Requests License


📝 Table of Contents

🧐 About

A simple and declarative way to provide complex, interactive animations for React Native.

<AnimatedText
  style={{
    color: "orange",
    fontSize: 48,
  }}
  animate={[
    {
      to: { transform: [{ scale: 1 }] },
      type: "SPRING",
      bounciness: 10,
      speed: 1,
    },
    {
      to: { color: "red" },
      duration: 150,
      loop: true,
    },
  ]}
>
  Welcome
</AnimatedText>

✅ List of Features

  • Simple: No need to deal with Animated.Values to make great animations.
  • Declarative: Describe your animations rather than build them.
  • Powerful: Run multiple independent animations at once.
  • Serializable: Schedule animations to follow one another.
  • Smooth: Use useNativeDriver for extra performance.
  • Type-Safe: Fully integrated with typescript out-of-the-box.

🏁 Getting Started

Prerequisites

Works with any project implementing React 16.8 onwards

Installing

npm i @huds0n/animations

🧑‍💻 Basic Usage

Base Style

Animated components style identically to their static counterpart. Updating style will immediately change the appearance of a component.

import { AnimatedView } from "@huds0n/animations";

// Inside component

<AnimatedView
  style={{
    height: 50,
    width: 100,
    backgroundColor: isSelected ? "red" : "blue",
  }}
/>;

Basic Animation

Passing an animationProps into animate will cause the component to transition to the new style. Animated Components will automatically detect and start animations on animate change.

<AnimatedView
  style={{
    backgroundColor: "blue",
    width: 100,
  }}
  animate={{
    to: {
      backgroundColor: "red",
      height: 50,
    },
    delay: 500,
    duration: 1000,
  }}
/>

Note that animations will intelligently calculate style property start values even if it is already in mid animation! However, it's important not to mix numbered dimensions with string dimensions. If no value is specified it assumes 0, '0%', '0deg', and 'transparent' for numbers, percentage dimensions, rotations, and colors respectively.

Looping

Loop can be added to an animationProps and can be easily controlled in three ways:

  • boolean - permanent looping;
  • number (multiples of 0.5) - select number of loops before stopping;
  • ref ({ current: boolean }) - detect and stops looping once set to false, e.g loopRef.current = false.
// Loop ref
const loopRef = useRef(true)

// Component
<AnimatedView
  style={{
    backgroundColor: 'blue',
    width: 100,
  }}
  animate={{
    to: {
      backgroundColor: 'red',
      height: 50,
    },
    delay: 500,
    duration: 1000,
    loop: loopRef,
  }}
/>

Parallel Animations

Multiple animations can be started at once on a component. To do this simply pass the animations in as an array.

<AnimatedView
  style={{
    backgroundColor: "blue",
    width: 100,
  }}
  animate={[
    {
      to: { height: 50 },
      delay: 500,
      duration: 1000,
    },
    {
      to: { backgroundColor: "red" },
      duration: 250,
      loop: true,
    },
  ]}
/>

Sequence Animations

To stack animations pass the following animationProps as a return value in the function onAnimationEnd.

<AnimatedView
  style={{
    height: 50,
    width: 100,
    backgroundColor: "blue",
  }}
  animate={{
    to: { height: 50 },
    delay: 500,
    duration: 1000,
    onAnimationEnd: () => ({
      to: { backgroundColor: "red" },
      duration: 250,
      loop: true,
    }),
  }}
/>

🧑‍🔬 Advanced Usage

Create Animated Component

Any component which has a style prop can be turned into an animated component using createAnimatedComponent.

import { Image } from "react-native";
import { createAnimatedComponent } from "@huds0n/animations";

const AnimatedImage = createAnimatedComponent(Image);

Use Native Driver

For extra performance pass in the useNativeDriver prop. However, this can only work if you are animating native driver compatible props, such as opacity and transforms.

<AnimatedView
  style={{
    backgroundColor: "blue",
    height: 100,
    width: 100,
  }}
  animate={{
    opacity: 1,
  }}
  useNativeDriver
/>

Attach Animations

Sometimes you may want to attach an animation to another Animated.Value, e.g. a touch event created by PanResponder. By using the attach prop you set styles at specific Animated.Value input points. The component will then animate fluidly between the input points.

<AnimatedView
  {...panResponder.panHandlers}
  attach={{
    at: [
      {
        input: -200,
        style: { backgroundColor: "blue", transform: [{ translateY: -200 }] },
      },
      {
        input: 0,
        style: { backgroundColor: "black" },
      },
      {
        input: 200,
        style: { backgroundColor: "red", transform: [{ translateY: 200 }] },
      },
    ],
    animatedValue: panY,
  }}
/>

For more complex animation paths you can set a style function to run over a set range of inputs. The smoothness of the path will depend on the number of points you chose but will require increasing calculations.

<AnimatedView
  attach={{
    over: {
      inputStart: -200,
      inputEnd: 200,
      points: 20,
      fn: (input) => ({
        transform: [
          { translateY: input },
          {
            translateX: Math.pow(input / 200, 3) * 80,
          },
        ],
      }),
    },
    animatedValue: panY,
  }}
/>

See example for use case with PanResponder.

📖 Reference

Animation Props

PropRequired/DefaultDescriptionType
to✔️Style to animate totextStyle or viewStyle
loopfalseSee loopingboolean, number, or number ref
onAnimationEnd-Called when animation endsPasses array of style props attached to animationAny animationProp returned is ran in sequence(attachedProps: string array) => void or animationProps
onAnimationStart-Called when animation starts() => void
type'TIMING'Type of animation method'TIMING', 'SPRING', or 'DECAY'

All Animation method specific props can also be used, such as duration, velocity, and friction.

🎁 Extras

ColorFader

Container extending React Native's View that smoothly animates background color.

<ColorFader backgroundColor={isSelected ? "red" : "blue"}>
  // View's children
</ColorFader>

Additional props:

PropRequired/DefaultDescriptionType
animatetrueToggles color animationboolean
animation{ type: 'TIMING', duration: 100}Color animation configAnimationProps with 'to'
backgroundColornullBackground colorstring or null
overrideColor-Overrides backgroundColor without animationstring

ContentsFader

Container extending React Native's View that fades between it's child components.

<ContentsFader dependencies={[isSelected]}>
  {isSelected && <SelectedComponent />}
  {!isSelected && <UnSelectedComponent />}
</ContentsFader>

Additional props:

PropRequired/DefaultDescriptionType
animatetrueToggles fade animationboolean
animationDuration500Duration of cross fadenumber
dependencies✔️Array of variables which on change invoke fadearray of any
easing-Animation easing(value: number) => number
fadeOverlap1/3Ratio of cross fade overlappingnumber
useNativeDrivertrueWhether animation uses native driverboolean

Transition

Combines ColorFader and ContentsFader with automatic resizing based on content size.

<TransitionContainer
  backgroundColor={currentButton.backgroundColor}
  style={{
    borderWidth: StyleSheet.hairlineWidth,
    height: 40,
    padding: 10,
    borderRadius: 10,
  }}
  dependencies={[currentButton.text]}
>
  <Text style={{ textAlign: "center" }}>{currentButton.text}</Text>
</TransitionContainer>

Lists

Adds animation attached to flatlist scroll with automatic animate in.

Additional props:

PropRequired/DefaultDescriptionType
animationDelay0Delay in ms on animating innumber
animationDuration2500Duration in ms of animating innumber
at-Set styles at position points to animate between(ElementPosition) => attachAtProp
itemLength✔️Length of item element in direction of scrollnumber
footerOffset-Footer offsetnumber
headerOffset-Header offsetnumber
ListComponentFlatListList component to animate (will inherit props)React List Component
offsetAnim-Scroll animated valueCan be attached to other Animated Components for complex animationsAnimated Value
onAnimationEnd-Called when animation in complete() => void
over-Set style function animate over(ElementPosition) => attachOverProp
renderItem✔️Item render functionPassed ElementPosition with ListRenderItemInfo(ElementPosition & ListRenderItemInfo) => React Component
useNativeDriverfalseWhether animation uses native driverboolean

ElementPosition:

PropDescriptionType
indexItem indexnumber
rowItem rownumber
startScroll offset at which the element is after the start of the viewnumber
endScroll offset at which the element is after the end of the viewnumber
<AnimatedList
  animationDuration={4000}
  itemLength={150}
  at={({ index, start, end }) => [
    /* At 150px above the top of the view items have an opacity 0.5 */
    { input: start + 150, style: { opacity: 0.5 } },

    /* When the item is in full view they have opacity 1 */
    { input: start, style: { opacity: 1 } },

    /* At 200px above the bottom of the view the items will start to fade from opacity 1 */
    {
      input: end + 200,
      style: { opacity: 1 },
    },

    /* At 100px above the bottom of the view the elements start their complex movement out */
    {
      input: end + 100,
      style: {
        transform: [
          { translateX: 0 },
          { translateY: 0 },
          { scale: 1 },
          { rotate: "0deg" },
        ],
      },
    },

    /* By the time the element reaches the bottom of the screen has completed it's complex movement.
    Note how remainder is use to calculate column */
    {
      input: end,
      style: {
        opacity: 0,
        transform: [
          { translateX: index % 2 ? 150 : -150 },
          { translateY: -150 },
          { scale: 0 },
          { rotate: index % 2 ? "-360deg" : "360deg" },
        ],
      },
    },
  ]}
  data={DEMO_DATA}
  keyName="value"
  numColumns={2}
  renderItem={({ item }) => {
    return (
      <View style={styles.itemContainer}>
        <Image source={{ uri: item.PICTURE_URI }} style={styles.itemPicture} />
      </View>
    );
  }}
  useNativeDriver
  reverseZIndex
  style={styles.flatlist}
/>

📲 Example

Clone or fork the repo at https://github.com/JontiHudson/modules-huds0n-animations

Go to the __example__ folder. Run npm install to install the expo project, then expo start to launch the example.

✍️ Authors

See also the list of contributors who participated in this project.

🎉 Acknowledgements

  • Special thanks to my fiance, Arma, who has been so patient with all my extra-curricular work.
1.6.0-beta53

2 years ago

1.6.0-beta54

2 years ago

1.6.0-beta60

2 years ago

1.6.0-beta61

2 years ago

1.6.0-beta63

2 years ago

1.6.0-beta46

2 years ago

1.6.0-beta47

2 years ago

1.6.0-beta48

2 years ago

1.6.0-beta49

2 years ago

1.6.0-beta42

2 years ago

1.6.0-beta44

2 years ago

1.6.0-beta45

2 years ago

1.6.0-beta50

2 years ago

1.6.0-beta51

2 years ago

1.6.0-beta52

2 years ago

1.6.0-beta35

2 years ago

1.6.0-beta36

2 years ago

1.6.0-beta37

2 years ago

1.6.0-beta38

2 years ago

1.6.0-beta31

2 years ago

1.6.0-beta40

2 years ago

1.6.0-beta26

2 years ago

1.6.0-beta21

2 years ago

1.6.0-beta13

2 years ago

1.5.1-beta3

3 years ago

1.5.1-beta.1

3 years ago

1.5.1-beta.2

3 years ago

1.5.0-beta.21

3 years ago

1.5.0-beta.20

3 years ago

1.5.0-beta.19

3 years ago

1.5.0-beta.18

3 years ago

1.5.0-beta.16

3 years ago

1.5.0-beta.15

3 years ago

1.5.0-beta.14

3 years ago

1.5.0-beta.13

3 years ago

1.4.6

3 years ago

1.4.5

3 years ago

1.4.4

3 years ago

1.4.3

3 years ago

1.4.2

3 years ago

1.4.1

3 years ago

1.4.0

3 years ago

1.3.4-beta.4

3 years ago

1.3.4-beta.3

3 years ago

1.3.4-beta.2

3 years ago

1.3.4-beta.1

3 years ago

1.3.3-beta.7

3 years ago

1.3.3-beta.6

3 years ago

1.3.3-beta.3

3 years ago

1.3.3-beta.5

3 years ago

1.3.3-beta.4

3 years ago

1.3.3-beta.2

3 years ago

1.3.2-beta.8

3 years ago

1.3.2-beta.7

3 years ago

1.3.2-beta.6

3 years ago

1.3.2-beta.5

4 years ago

1.3.2-beta.4

4 years ago

1.3.2-beta.3

4 years ago

1.3.2-beta.1

4 years ago

1.3.1-beta.24

4 years ago

1.3.1-beta.23

4 years ago

1.3.1-beta.21

4 years ago

1.3.1-beta.22

4 years ago

1.3.1-beta.20

4 years ago

1.3.1-beta.16

4 years ago

1.3.1-beta.17

4 years ago

1.3.1-beta.15

4 years ago

1.3.1-beta.11

4 years ago

1.3.1-beta.9

4 years ago

1.3.1-beta.7

4 years ago

1.3.1-beta.6

4 years ago

1.3.0-beta.21

4 years ago

1.3.0-beta.22

4 years ago

1.3.0-beta.20

4 years ago

1.3.0-beta.19

4 years ago

1.3.0-beta.18

4 years ago

1.3.0-beta.17

4 years ago

1.3.0-beta.16

4 years ago

1.3.0-beta.15

4 years ago

1.3.0-beta.12

4 years ago

1.3.0-beta.13

4 years ago

1.3.0-beta.10

4 years ago

1.3.0-beta.7

4 years ago

1.3.0-beta.6

4 years ago

1.3.0-beta.4

4 years ago

1.3.0-beta.5

4 years ago

1.2.0-beta.23

4 years ago

1.2.0-beta.20

4 years ago

1.3.0-beta.2

4 years ago

1.3.0-beta.3

4 years ago

1.2.0-beta.19

4 years ago

1.2.0-beta.18

4 years ago

1.2.0-beta.17

4 years ago

1.2.0-beta.16

4 years ago

1.2.0-beta.15

4 years ago

1.2.0-beta.12

4 years ago

1.2.0-beta.14

4 years ago

1.2.0-beta.13

4 years ago

1.2.0-beta.9

4 years ago

1.2.0-beta.8

4 years ago

1.2.0-beta.7

4 years ago

1.2.0-beta.6

4 years ago

1.2.0-beta.5

4 years ago

1.2.0-beta.4

4 years ago

1.3.0-beta.1

4 years ago

1.2.0-beta.3

4 years ago

1.2.0-beta.2

4 years ago

1.2.0

4 years ago

1.1.0

4 years ago

1.0.0

4 years ago