DEV Community

Cover image for Creating a ViewPager using FlatList
Gabriel Menezes da Silva
Gabriel Menezes da Silva

Posted on

Creating a ViewPager using FlatList

Motivation

At my job, a demand appeared where I needed to create a modal that should have a ViewPager to demonstrate a three step tutorial for a functionality within the app.
I checked that there is a react-native's library that provides the ViewPager component ready. But as the project has a lot of libs already, I always try to not put unnecessary libs, in order to maintain the size of the bundle as small as possible. Therefore, as I know that I would not need all functionalities of the ViewPager, which are a lot, I searched how I would create one, in which I had three pages where I would swipe to right or left and the page was changed, all of this just with components that exists in react-native already.

ViewPager

To better understand what is a ViewPager, I decided to put the gif below. I got this .gif from this repository (https://github.com/afollestad/viewpagerdots) :
ViewPager

I believe that a lot of people saw this component already, since this component is very common in the tutorial session of the applications.

Let's Code

First, I'm going to create a button where when pressed, a modal with the ViewPager will show up:


<Pressable
        style={styles.openViewPagerModalButton}
      >
        <Text>Open the most awesome view pager modal!</Text>
</Pressable>
Enter fullscreen mode Exit fullscreen mode

For this example, I created an array with the objects that represents the text which will appear in each page:

const texts = [
    {
      id: "1",
      text: "Teste 1",
    },
    {
      id: "2",
      text: "Teste 2",
    },
    {
      id: "3",
      text: "Teste 3",
    },
  ];
Enter fullscreen mode Exit fullscreen mode

I created a state that is going to control the visibility of the modal:

 const [viewPagerModalIsVisible, setViewPagerModalIsVisible] = useState(true);
Enter fullscreen mode Exit fullscreen mode

Right below is the frosting on the cake 🍰:

<Modal visible={viewPagerModalIsVisible}>
        <View style={styles.modalMainContainer}>
          <View style={styles.modalSubContainer}>
            <FlatList
              contentContainerStyle={styles.alignItemsCenter}
              data={texts}
              horizontal
              keyExtractor={(item) => item.id}
              pagingEnabled
              showsHorizontalScrollIndicator={false}
              renderItem={({ item }) => (
                <Text style={styles.viewPagerTextStyle}>{item.text}</Text>
              )}
            />
          </View>
       </View>
</Modal>
Enter fullscreen mode Exit fullscreen mode

Basically, I created a FlatList where its scroll is horizontal, using the prop horizontal, and with pagination, using the prop pagingEnabled. Each item of the list, which has the style viewPagerTextStyle, has the size of the View with style modalSubContainer, making the list behave not as a continuous scroll but as a ViewPager. That is, you just have to swipe to the right or to the the left that the page will change accordingly.
This behavior is shown in the gif below:

t_video5120910380561858722

Stylization code of modalSubContainer and viewPagerTextStyle:

 modalSubContainer: {
    backgroundColor: "#FFF",
    alignSelf: "center",
    alignItems: "center",
    justifyContent: "center",
    height: 190,
    width: 320,
    borderTopRightRadius: 20,
    borderTopLeftRadius: 20,
    paddingTop: 10,
  },
viewPagerTextStyle: {
    width: 320,
    textAlign: "center",
  },
Enter fullscreen mode Exit fullscreen mode

Indication of pages

To be exactly equal to a ViewPager we have to add that "small dots" which indicates the page that the user is. To do this, we're going to add a lib called react-native-dots-pagination. To install it, just use the command below if you use yarn:

yarn add react-native-dots-pagination
Enter fullscreen mode Exit fullscreen mode

If you use npm:

npm install react-native-dots-pagination
Enter fullscreen mode Exit fullscreen mode

It must be created a state that is going to control which pagination dot is active:

 const [activeDot, setActiveDot] = useState(0);
Enter fullscreen mode Exit fullscreen mode

Before adding the "small dots" in my screen, I need to know which page of my list the user is, in order to do this, I need to add the props onViewableItemsChanged and viewabilityConfig in the FlatList:

<FlatList
  contentContainerStyle={styles.alignItemsCenter}
  data={texts}
  horizontal
  keyExtractor={(item) => item.id}
  pagingEnabled
  onViewableItemsChanged={handleVieweableItemsChanged}
  viewabilityConfig={viewabilityConfig}
  showsHorizontalScrollIndicator={false}
  renderItem={({ item }) => (
  <Text style={styles.viewPagerTextStyle}>{item.text}</Text>
)}
  />
Enter fullscreen mode Exit fullscreen mode

The prop onViewableItemsChanged is to execute a function each time the visibility of a list's item changes. In our case, each time we change the page, the function handleVieweableItemsChanged is called:

const handleVieweableItemsChanged = useCallback(({ viewableItems }) => {
    setActiveDot(viewableItems[0].index);
  }, []);
Enter fullscreen mode Exit fullscreen mode

When this function gets executed the active pagination dot changes, that is, when the user is in the first page, the first dot is shown as active and the same happens with the other pages.

The prop viewabilityConfig is used to inform a lot of parameters which are going to influence the prop onViewableItemsChanged. For this case, I'm sending the prop viewabilityConfig an object with an attribute which informs how much of the item must be shown for it to be considered as visible. The name of this attribute is itemVisiblePercentThreshold:

  const viewabilityConfig = {
    itemVisiblePercentThreshold: 50,
  };
Enter fullscreen mode Exit fullscreen mode

Just 50% of the item must be visible to the function handleVieweableItemsChanged be called.

The pagination dots component code is below:

    <Dots
     activeDotWidth={6}
     activeDotHeight={6}
     passiveDotHeight={6}
     passiveDotWidth={6}
     length={3}
     activeColor={"#000"}
     active={activeDot}
     />
Enter fullscreen mode Exit fullscreen mode

Complete code of the app: https://github.com/gabrielsideprojects/awesome-view-pager-flat-list
I'm open to pull request and suggestions to the code and article. Make yourself confortable πŸ˜ƒ.
I used Expo to create the app.
Let's drink a cozy and warm coffee, say hi to me on LinkedinπŸ˜ƒ β˜•.

Top comments (0)