Development

Cómo Crear un Carousel en React Native desde Cero sin Librerías

Creación de un Carousel en React Native sin Librerías Externas

Los carousels son elementos comunes en las aplicaciones móviles que permiten a los usuarios desplazarse de forma horizontal entre diferentes elementos, como imágenes o tarjetas de producto. Aunque existen muchas librerías disponibles para crear carousels en React Native, en este tutorial aprenderemos a crear uno desde cero sin depender de ninguna librería externa. Carusel react native Creamos un componente Carousel en Carousel.tsx

javascript
import React, { useState, useRef } from 'react'; import { Dimensions, FlatList, TouchableOpacity, View } from 'react-native'; import { MaterialIcons } from '@expo/vector-icons'; export type ISliderItem = { [key: string]: any; } type RenderItemProps = { item: ISliderItem; onPress: (item: ISliderItem) => void; }; type SliderProps = { items: ISliderItem[] onPress: (item: ISliderItem) => void; renderItem: ({ item, onPress }: RenderItemProps) => JSX.Element; dots?: boolean; arrows?: boolean; dotsFloating?: boolean; } const { width: windowWidth } = Dimensions.get('window'); const Carousel = (props) => { // EVENTOS, ESTADOS Y FUNCIONES // ... // RENDER return(...) } export default Carousel

Definimos las funciones, eventos y los estados que estamos vamos usar para este ejemplo

javascript
const { items = [], onPress, dots = true, arrows = true, dotsFloating = false } = props; const [currentPage, setCurrentPage] = useState(0); const flatListRef = useRef(null); const _spacing = 0; // Funciones para cambiar de página const handlePageChange = (newPage) => { setCurrentPage(newPage); flatListRef.current?.scrollToIndex({ index: newPage, animated: true }); }; const goToNextPage = () => { if (currentPage < items.length - 1) { const nextPage = currentPage + 1; setCurrentPage(nextPage); flatListRef.current?.scrollToIndex({ index: nextPage, animated: true }); } }; const goToPreviousPage = () => { if (currentPage > 0) { const previousPage = currentPage - 1; setCurrentPage(previousPage); flatListRef.current?.scrollToIndex({ index: previousPage, animated: true }); } };

para este ejemplo vamos usar el FlatList de React Native para mostrar los elementos del carousel de manera horizontal.

javascript
// prevButton arrow <FlatList ref={flatListRef} style={{ flexGrow: 0 }} data={items} keyExtractor={(item) => item.id} horizontal pagingEnabled renderItem={({ item }) => renderItem({ item, onPress })} showsHorizontalScrollIndicator={false} contentContainerStyle={{ paddingLeft: _spacing }} onMomentumScrollEnd={(event) => { const newPage = Math.round(event.nativeEvent.contentOffset.x / windowWidth); setCurrentPage(newPage); }} /> // NextButton arrow // DOTS

Ahora definiremos las secciones de navegación arrows y los dots del carousel.

javascript
// prevButton {arrows ? ( <TouchableOpacity onPress={goToPreviousPage} style={[styles.navigationButton, styles.leftButton]} > <MaterialIcons name="arrow-back-ios" size={16} color="black" /> </TouchableOpacity> ) : null} // NextButton {arrows ? ( <TouchableOpacity onPress={goToNextPage} style={[styles.navigationButton, styles.rightButton]} > <MaterialIcons name="arrow-forward-ios" size={16} color="black" /> </TouchableOpacity> ) : null} // Dots {dots ? ( <View style={[styles.dotContainer, dotsFloating && styles.dotContainerFloating]}> {items.map((_, index) => ( <TouchableOpacity key={index} style={[ styles.dot, index === currentPage && styles.activeDot ]} onPress={() => handlePageChange(index)} /> ))} </View> ) : null}

Ahora agreamos los estilos base para nuestro carousel.

Crear un archivo styles.ts

javascript
import { StyleSheet } from "react-native"; import { theme } from "@components/theme"; const { colors } = theme; export const styles = StyleSheet.create({ contentContainerStyle: { width: "100%", }, dotContainer: { flexDirection: "row", justifyContent: "center", alignItems: "center", marginTop: 10, }, dot: { width: 10, height: 10, borderRadius: 5, backgroundColor: "#E1E1E1", marginHorizontal: 5, }, navigationButton: { position: "absolute", top: "40%", paddingHorizontal: 5, paddingVertical: 5, borderRadius: 10, zIndex: 2, }, leftButton: { left: 10, flex: 1, }, rightButton: { right: 10, }, activeDot: { backgroundColor: colors.primary.red, width: 32, }, dotContainerFloating: { bottom: 30, }, });

Ejemplo de uso

para mi prueba tengo un carousel de imagenes, para esto tengo lo siguiente

javascript
export default function Demo() { const images = [ { id: "image-1", "_type": "image", "alt": "", "link": "", "title": ", " }, ... ] function ProductImage({ image }: ProductImageProps) { const { link, alt } = image; return ( <View style={{ ...styles.container, width: windowWidth }}> <Image source={{ uri: link }} style={styles.image} alt={alt} /> </View> ) } return( <View style={styles.container} > <Carousel items={images} dotsFloating={false} arrows={false} onPress={(item) => { console.log('item: ', item); }} renderItem={({ item }: any) => ( <ProductImage image={item} onPress={() => { console.log('item: ', item); }} /> )} /> </View> ) } const styles = StyleSheet.create({ container: { width: "90%", backgroundColor: "#fff", }, image: { width: 244, height: 260, resizeMode: "stretch", alignSelf: "center", }, });

Deja tu comentario!

Su dirección de correo electrónico no será publicada.