Timeless
Published in

Timeless

Building a Share Button Interaction Concept using React Native and Software Mansion’s Reanimated — I

Hey there! If you’re a fan of React Native Animations and looking for some nice inspiration for your next project, you’re in the right place.

In this post, we’ll be exploring a simple yet cool share button interaction concept using React Native and Software Mansion’s Reanimated library.

This concept was inspired by the talented @Volorf and their Dribble shot, which you can check out here

We’ll be breaking down how to create this interactive and visually appealing button, step by step in a two-part blog series. So hang in there and I will get you through.

Cover Image Fayas fs

Setting up React Native Project

Creating a new React Native Project

react-native init MyProject

You can replace “MyProject” with your desired name. The above command will create and initialize a new React Native Project.

Installing the dependencies

Up next, navigate to the root directory of your React Native project and install the dependencies using the following commands.

cd MyProject

npm install --save react-native-gesture-handler reanimated react-native-linear-gradient react-native-svg twrnc

Linking dependencies by running

npx pod install

Start the development server

Start the development server by running the following command

react-native start

This will start the development server and allow you to run your app on a simulator or device.

To run your app on an iOS simulator, run the following command

react-native run-ios

To run your app on an Android emulator or device, run the following command from the root directory of your project:

react-native run-android

That’s it! Your React Native project is now set up. Let's get coding!!

I would like to split the blog into sections.

Building the Card

The Shareable Card

The card is built using Linear Gradient and some text on top.
It is very simple, where I would have mentioned the start and end points of the gradient and used an angle too.

I would have set multiple colors picked from the tailwind library, resulting in a gradient like the above. (I don't think it is that good)

The whole card will be wrapped inside a <Pressable /> component from React Native if you want to make the whole card interactable.

<AnimatedLinearGradient
style={tailwind.style('p-5 rounded-lg')}
start={{x: 0.0, y: 0.25}}
end={{x: 0.5, y: 1.0}}
angle={65}
useAngle={true}
colors={[
tailwind.color('text-violet-700') as string,
tailwind.color('text-violet-500') as string,
tailwind.color('text-violet-600') as string,
tailwind.color('text-violet-500') as string,
tailwind.color('text-violet-700') as string,
]}>
<Animated.Text style={tailwind.style('text-white')}>
Earnings today
</Animated.Text>
<Animated.Text style={tailwind.style('text-white text-5xl pt-6')}>
₹10,421.56
</Animated.Text>
<Animated.View
style={tailwind.style('flex flex-row items-center pt-2')}>
<Animated.View
style={tailwind.style('px-1 py-0.5 bg-violet-800 rounded-md')}>
<Animated.Text
style={tailwind.style('text-white text-sm tracking-wider')}>
+1.5%
</Animated.Text>
</Animated.View>
<Animated.Text
style={tailwind.style('text-white text-sm tracking-wide pl-1')}>
Higher earnings than usual
</Animated.Text>
</Animated.View>
</AnimatedLinearGradient>

Building the Menu/Close Icon

This component comprises two <Animated.View />.

The first animated view is absolutely positioned in the top right of the card which is responsible for a ripple effect.

The second animated view component comprises Two Gesture Detectors from react-native-gesture-handler, the first contains the ShareIcon and the second has a CloseIcon and has shareTapHandler and closeTapHandler configured respectively.

There are multiple things happening on each handler to give the right animation feel. Let me first talk about the handlers.

`shareTapHandler` & `closeTapHandler`

To define a handler we use the Gesture.Tap() method from the react-native-gesture-handler library.

const shareTapHandler = Gesture.Tap()
.maxDistance(1)
.onStart(() => {
'worklet';
iconState.value = withSpring(0, SHARE_SPRING_CONFIG);
})
.onTouchesUp(() => {
rippleStateScale.value = withTiming(1, {
duration: 300,
easing: Easing.out(Easing.ease),
});
})
.onFinalize(() => {
rippleStateOpacity.value = withTiming(
0,
{duration: 500, easing: Easing.out(Easing.ease)},
() => {
rippleStateOpacity.value = 1;
rippleStateScale.value = 0;
},
);
});
const closeTapHandler = Gesture.Tap()
.maxDistance(1)
.onStart(() => {
'worklet';
iconState.value = withSpring(1, CLOSE_SPRING_CONFIG);
})
.onTouchesUp(() => {
rippleStateScale.value = withTiming(1, {
duration: 300,
easing: Easing.out(Easing.ease),
});
})
.onFinalize(() => {
rippleStateOpacity.value = withTiming(
0,
{duration: 500, easing: Easing.out(Easing.ease)},
() => {
rippleStateOpacity.value = 1;
rippleStateScale.value = 0;
},
);
});

The maxDistance()is set to 1 for both handlers, which determines the max distance the user’s finger can move while still registering the tap.

The onStart() is triggered when the user starts the tap gesture. In this function I set an Animated Shared Value, iconState to 0/1 using the withSpring function of reanimated library.

The iconState.value is responsible for the state of the Menu Icon, i.e. open or closed state.

The Container Width Manipulation

We use the useAnimatedStyle hook from reanimated library to achieve animating width.

const containerStyle = useAnimatedStyle(() => {
return {
width: interpolate(iconState.value, [1, 0], [40, 144]),
};
});

The above code gives us an animated style variable containerStyle that has a single-style property width which is animated using the interpolate method from the reanimated library.

The interpolate function of reanimated library takes in three arguments: a value that changes over time: iconState.value , an input range: [1, 0] and an output range: [40, 144].

In our case, we have changed the iconState.value using the spring animation to 0/1. So the width property of the animated style object will change from 40 to 144.

This will cause the width property of the animated style objects to change accordingly, animating the width of the container view from 40 units to 144 units over the duration of the spring animation.

The `ShareIcon` and `CloseIcon` Manipulation

We use the same useAnimatedStyle to apply the toggle styles between the ShareIcon and CloseIcon.

const shareIconStyle = useAnimatedStyle(() => {
return {
opacity: interpolate(iconState.value, [0, 1], [0, 1]),
zIndex: interpolate(iconState.value, [0, 1], [0, 9999]),

transform: [{scale: interpolate(iconState.value, [0, 1], [0.7, 1])}],
};
});

const closeIconStyle = useAnimatedStyle(() => {
return {
opacity: interpolate(iconState.value, [1, 0], [0, 1]),
zIndex: interpolate(iconState.value, [1, 0], [0, 9999]),
transform: [{scale: interpolate(iconState.value, [1, 0], [0.7, 1])}],
};
});

The above both hooks animate the same three properties of the style object: opacity, zIndex, and transform.

In the shareIconStyle, the opacity property is animated using the interpolate function using the iconState.value from the input range [0, 1] to the output range of [0,1]. This causes the opacity of the Share Icon change from 0 to 1 as iconState.value changes from 0 to 1.

The zIndex, property also uses the interpolate() which maps the same iconState.value from the input range of [0, 1] to the output range of [0, 9999]. This makes the whole decision of which icon should be placed forward based on the iconState.value.

The transform property is applied to scale down the icon a little before it fades out and gives way to the other icon. The scale property is animated using the interpolate method, which maps the changing value of iconState.value from the input range of [0, 1] to the output range of [0.7, 1].

The closeIconStyle(), is very similar to the shareIconStyle() but the input and output ranges for the interpolation are just reversed. This enables all the properties to toggle between the two icons, CloseIcon and ShareIcon.

Finally, we end up getting this interaction.

The Initial Menu Interaction

Well in this first part, we have set up a react native project and installed the necessary dependencies. Then we walked through the steps for building the card, and how to Animate the Share/Close icon.

In the next part, we will look at how to add a ripple animation on tap and get some share icons in the empty space.

This is Karthik from Timeless

I hope you found this blog post helpful and informative. If you have any feedback or suggestions, please leave a comment below. I’d love to hear your thoughts and opinions on the topic.

And if you have any ideas for future blog posts, let me know! I’m always looking for new and interesting topics to explore.

Thank you for reading, and I look forward to hearing from you. :)

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Karthik Balasubramanian

Trying to Solve Problems with Code @ timeless.co. Open sourcing the solutions when possible.