Criando um ViewPager utilizando FlatList

gabrielsideprojects

Gabriel Menezes da Silva

Posted on December 29, 2020

Criando um ViewPager utilizando FlatList

Motivação

No meu trabalho apareceu uma demanda em que eu tinha que criar um pequeno modal, onde houvesse um "ViewPager" para demonstrar um pequeno tutorial de uma funcionalidade em 3 passos.
Verifiquei que já existe uma lib para react-native que fornece o componente de ViewPager já pronto. Mas como o projeto já tem muitas libs, tento sempre procurar não adicionar libs desnecessárias, com o intuito de manter o tamanho do bundle do app o menor possível. Assim, como eu sabia que não precisaria de todas as funcionalidade de uma ViewPager, que são muitas, pesquisei como eu poderia criar uma, em que tivesse três páginas onde eu desse um "swipe" para direita ou para esquerda e a página fosse mudada, isso tudo apenas com componentes já existentes do react-native.
Uma das maiores motivações para a criação deste artigo também é que não achei muito conteúdo em português abordando este assunto.

ViewPager

Para um melhor entendimento do que seria um ViewPager decidi colocar o gif abaixo. Consegui esse .gif a partir deste repositório (https://github.com/afollestad/viewpagerdots) :
ViewPager
Acredito que muitos já viram, esse componente é muito comum na parte de tutorial das aplicações.

Vamos codar

Primeiramente, irei criar apenas um botão onde será possível clicar para aparecer o modal onde haverá a tão citada "ViewPager":


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

Para exemplificar, criei um array de objetos que contém o texto que aparecerá em cada "página":

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

Criei um estado que vai controlar a visibilidade do modal:

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

E logo abaixo segue o código da cereja do bolo 🍒:

<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

Basicamente, criei uma FlatList em que seu scroll é horizontal, usando a prop horizontal, e com paginação, usando a prop pagingEnabled. Cada item da lista, com o estilo viewPagerTextStyle, tem a largura da View de estilo modalSubContainer, fazendo com que a lista se comporte não como um scroll contínuo mas como um ViewPager, ou seja, basta dar um swipe para direita ou esquerda que a página será passada para o lado correspondente. Esse comportamento está demonstrado no gif abaixo:
t_video5120910380561858722

Código de estilização do modalSubContainer e do 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

Indicação das páginas

Para ficar exatamente igual a um ViewPager temos que adicionar aqueles "pontinhos" que indicam qual página o usuário está. Para isso, vamos adicionar uma lib chamada react-native-dots-pagination (https://github.com/tsepeti/react-native-dots-pagination). Para instalá-la, basta usar o comando abaixo caso você use o yarn:

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

Case você utilize o npm:

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

Deve ser criado um state que controlará o "pontinho" que está ativo:

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

Antes de adicionar os "pontinhos" na tela, eu preciso saber em qual "página" minha lista está, para isso, preciso adicionar as props onViewableItemsChanged e viewabilityConfig na 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

A prop onViewableItemsChanged serve para executar uma função toda vez que a visibilidade de cada item da lista mudar. Para o nosso caso, toda vez que mudarmos de página, a função handleVieweableItemsChanged será chamada:

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

Quando essa função for executada será alterado o "pontinho" que está ativo, ou seja, quando estiver na primeira página, o primeiro "pontinho" será ativado e assim respectivamente.

A prop viewabilityConfig é usada para informar diversos parâmetros que irão influenciar na prop onViewableItemsChanged. Para o nosso caso irei criar um objeto, para passar na prop, com um o atributo que informa o quanto do item é necessário está disposto no layout para informar que o mesmo está visível. O nome desse atributo é itemVisiblePercentThreshold:

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

Basta 50% do item já está visível que a função handleVieweableItemsChanged será chamada.

O componente para os "pontinhos" segue logo abaixo:

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

Link para o código completo: https://github.com/gabrielsideprojects/awesome-view-pager-flat-list
Estou aberto a pull requests e sugestões para o código e o artigo. Sintam-se à vontade 😃.
Utilizei o Expo para a criação do aplicativo.
Para tomarmos um café bem quentinho, só mandar um "oi" lá no meu Linkedin 😃 ☕.

💖 💪 🙅 🚩
gabrielsideprojects
Gabriel Menezes da Silva

Posted on December 29, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related