Criando um ViewPager utilizando FlatList
Gabriel Menezes da Silva
Posted on December 29, 2020
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) :
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>
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",
},
];
Criei um estado que vai controlar a visibilidade do modal:
const [viewPagerModalIsVisible, setViewPagerModalIsVisible] = useState(true);
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>
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:
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",
},
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
Case você utilize o npm:
npm install react-native-dots-pagination
Deve ser criado um state que controlará o "pontinho" que está ativo:
const [activeDot, setActiveDot] = useState(0);
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>
)}
/>
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);
}, []);
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,
};
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}
/>
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 😃 ☕.
Posted on December 29, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.