NativeBase X Moti
View more posts
September 8, 2022 5 minute read

NativeBase X Moti

sankalp@geekyants.com
Sankalp Pandey
Software Engineer
NativeBase and Moti share a common goal — bringing universality to application development while removing redundant workflows. Therefore, we decided to conduct an experiment that explores how an app-development team can leverage both platforms. We are going to do this by animating a button that changes padding when clicked.

Experiment Methodology

⭐ Moti, by Fernando Rojo, is a universal animation package for React Native. It uses reanimated for high performance and eliminates the need to write code for different platforms. ⭐ NativeBase provides universal UI components that focus on utility.
Our goal was to analyze the ease of animating a NativeBase component using Moti. We tested the Background Change animation using design tokens (aka. values or constants needed to construct a design system). The pseudo props of NativeBase made the code succinct.
 
💡
Resources
🧰 Installation links for the two libraries:
 
⭐ Important characteristics of Moti to remember:
  • Universal: works on all platforms
  • 60 FPS animations run on the native thread
  • Mount/unmount animations, like Framer Motion
  • Powered by Reanimated 2
  • Intuitive API
  • Variant & keyframe animations
  • Strong TypeScript support
  • Highly-configurable animations
  • Sequence animations
  • Loop & repeat animations
  • Web support
  • Expo support
  • Next.js support

Experiment

NativeBase is highly versatile. It is a UI component library that supports cross-platform development with a single codebase. Moti also shares a similar philosophy—write once, animate everywhere.
We wanted to test how these libraries complement each other by animating padding properties with help of Moti animation. NativeBase Factory was used to make our own custom component that could pair with Moti.

Animation

 
The code below reflects how we have used a Nativebase component Factory to make our own custom component FactoryMotiNativeBaseView ⤵️
const FactoryMotiNativeBaseView = Factory(MotiView);
const NBMotiView = ({
  from,
  to,
  transition,
  animate,
  children,
  ...props
}: any) => {
  const ConvertTokenizedStyleToStyle = (StyleObject) => {
    const [style, ...restProp] = useStyledSystemPropsResolver(StyleObject);
    return { ...style, ...restProp[0].dataSet };
  };
Animated button component.
Making the custom component was tricky. We had to find a way to use Moti’s animation props with NativeBase. Using useStyledSystemPropsResolver was the solution.
This hook converted Moti’s animation props into props that Nativebase can accept. The code below details how we made it happen ⤵️
const NBMotiView = ({
  from,
  to,
  transition,
  animate,
  children,
  ...props
}: any) => {
  const ConvertTokenizedStyleToStyle = (StyleObject) => {
    const [style, ...restProp] = useStyledSystemPropsResolver(StyleObject);
    return { ...style, ...restProp[0].dataSet };
  };

  const resolvedProps = {
    from: ConvertTokenizedStyleToStyle(from),
    animate: ConvertTokenizedStyleToStyle(animate),
    transition: { type: "timing", duration: 1000, delay: 10 },
  };
The full animation of the video is shown below. ⤵️
 

Full Code Snippet of the Animation

import React, { useState } from "react";
//@ts-ignore
import { useStyledSystemPropsResolver } from "native-base/src/hooks/useStyledSystemPropsResolver.ts";
import { MotiView } from "moti";
import { Text, Factory, VStack, Pressable } from "native-base";

const FactoryMotiNativeBaseView = Factory(MotiView);
const NBMotiView = ({
  from,
  to,
  transition,
  animate,
  children,
  ...props
}: any) => {
  const ConvertTokenizedStyleToStyle = (StyleObject) => {
    const [style, ...restProp] = useStyledSystemPropsResolver(StyleObject);
    return { ...style, ...restProp[0].dataSet };
  };

  const resolvedProps = {
    from: ConvertTokenizedStyleToStyle(from),
    animate: ConvertTokenizedStyleToStyle(animate),
    transition: { type: "timing", duration: 1000, delay: 10 },
  };
  return (
    <Pressable
      onPress={() => {
        props.toggleHandler();
      }}
    >
      <FactoryMotiNativeBaseView {...resolvedProps} {...props}>
        {children}
      </FactoryMotiNativeBaseView>
    </Pressable>
  );
};
export default function ExitBeforeEnter() {
  const [visible, setVisible] = useState(true);
  const toggleHandler = () => {
    setVisible(!visible);
  };
  return (
    <VStack justifyContent={"center"} alignItems="center" flex={1}>
      <NBMotiView
        from={{
          p: visible? "5" : "10",
        }}
        animate={{
          p: visible? "10" : "5",
        }}
        transition={{ type: "timing", duration: 1000, delay: 10 }}
        bg="blue.200"
        toggleHandler={toggleHandler}
      >
        <Text>Animated Button</Text>
      </NBMotiView>
    </VStack>
  );
}
 

Verdict

NativeBase and Moti are terrific for creating animations on the web and native apps. It is cumbersome to add animation to an application with React Reanimated and animated V2 alone.
Moti simplifies the animator's workflow and NativeBase gives a great selection of UI components. It is a perfect match.