Building animated filters bar with React Native

and React Native Web

Anton Kalinin
JOB TODAY
3 min readApr 21, 2019

--

At JOB TODAY we are using React Native for Web and Mobile development. We’ve been talking about the unification process we went through in the previous article.

In this post I would like to describe the way we built animated filters bar using React Native (both for native and mobile web apps). I hope you’ll find it practical.

Here are a few examples in case you want to check them out first:

Layout

The main idea is to place fixed element over the top of the ScrollView which has left padding equal to the width of the sticky element.

Then wrap fixed element into Animated.View to make it work as a mask to hide part of the button while scrolling. In our case the mask has minimum width equal to the width of the filters icon.

There might be problem if filter’s sticky button has non determined width (for instance in case of different word length for different languages). So we can either predefine the map with widths of the buttons according to language or set onLayout to Animated.View to determine width of the button as if it’s been rendered for the first time.

Animation

So we want our fixed element to squeeze as we scroll filters bar. To achieve this we are going to animate width of the fixed element container that will operate like a mask for inner button.

The first part is pretty much trivial. We define new animated value as animatedWidth. In onFiltersScroll listener added as onScroll prop to ScrollView we change animatedWidth according to ScrollView content offset.

The main challenge is to handle the use case of releasing a finger by user while our sticky element is partially hidden. It’s either finishing the squeezing process or showing back the entire element.

So the overall tactic is to listen onScrollEndDrag event and decide the direction to scroll our ScrollView according to the content offset. As soon as user scrolls less than 1/2 of the button and stops we force scroll back, otherwise scroll forward and squeeze the button to its minimum size.

To make this behaviour look more natural we introduce a velocity factor: we put the horizontal velocity into equation to minimise the distance that shows in which direction to force scroll of the list.

Is there a way to use the same component for Web?

No doubt. It’s offered by React Native Web which is really cool by the way.
But to make your web experience smooth enough there are some aspects you need to take into account.

For instance we use TouchableOpacity for filter buttons in React Native apps. In fact I would not use same component for web because this usage leads to “shaking behaviour” during rapid scrolling. It’s caused by opacity css property that triggers a lot of repaints during the animation. In this case I would rather suggest to change TouchableOpacity to TouchableHighlight for web.

For instance:

import { TouchableOpacity, TouchableHighlight } from "react-native";const Touchable = Platform.select({
web: TouchableHighlight,
default: TouchableOpacity
});

Here is a GitHub repo with code of an example I mentioned above: https://github.com/jobtoday/animated-filters-example

That’s pretty much it. Hope, you’ve found it useful.

Let me know in the comments below what you think!

--

--