11. 1.Componente ScrollView 2 min Reproducir 12
Tutorial: Componente ScrollView en React Native
📱 Parte 11: Componente ScrollView - Dominando el Desplazamiento
🎯 Objetivo:
Aprender a usar ScrollView para crear contenido desplazable en React Native, entender las diferencias entre scroll vertical y horizontal, y aplicar buenas prácticas en el desarrollo.
📸 Entendiendo ScrollView desde la Imagen
Observando la imagen de VS Code y la aplicación:
text
┌─────────────────────────────────┐
│ 📱 PANTALLA VISIBLE │
│ │
│ "Step One" │
│ "See Your Changes" │
│ "Debug" │
│ "Learn More" │
│ "The Basics" │
│ │
│ ↓ │
│ ↓ CONTENIDO OCULTO ABAJO │
│ ↓ "Style" "Layout" "Resources" │
└─────────────────────────────────┘
Sin ScrollView: Solo ves lo que cabe en pantalla
Con ScrollView: ¡Puedes desplazarte para ver todo el contenido!
🚀 Paso 1: ¿Qué es ScrollView?
ScrollView es un contenedor desplazable que permite mostrar contenido más grande que la pantalla del dispositivo.
1.1 Importación Básica
javascript
import React from 'react';
import { ScrollView, View, Text, StyleSheet } from 'react-native';
📱 Paso 2: ScrollView Vertical (Por Defecto)
2.1 Ejemplo del Código de la Imagen
javascript
// Como en App.js de la imagen
const App = () => {
return (
<SafeAreaView>
<ScrollView> {/* ¡ESTO ES LO QUE PERMITE DESPLAZARSE! */}
<View style={styles.sectionContainer}>
<Text style={styles.sectionTitle}>Step One</Text>
<Text style={styles.sectionDescription}>
Edit App.js to change this screen.
</Text>
</View>
<View style={styles.sectionContainer}>
<Text style={styles.sectionTitle}>See Your Changes</Text>
<Text style={styles.sectionDescription}>
Double tap R on your keyboard to reload.
</Text>
</View>
{/* MÁS CONTENIDO ABAJO... */}
<View style={styles.sectionContainer}>
<Text style={styles.sectionTitle}>Learn More</Text>
<Text style={styles.sectionDescription}>
Read the docs to discover what to do next.
</Text>
</View>
{/* Y AÚN MÁS CONTENIDO... */}
<View style={styles.sectionContainer}>
<Text style={styles.sectionTitle}>The Basics</Text>
<Text>Style - Covers how to make it look good</Text>
<Text>Layout - How to arrange components</Text>
<Text>Resources - Useful tools and libraries</Text>
<Text>Components - Building blocks</Text>
<Text>Navigation - How to move between screens</Text>
</View>
</ScrollView>
</SafeAreaView>
);
};
2.2 DEMOSTRACIÓN: Con y Sin ScrollView
javascript
import React, { useState } from 'react';
import { View, Text, Button, ScrollView } from 'react-native';
const DemoScrollView = () => {
const [showScrollView, setShowScrollView] = useState(true);
const Content = () => (
<>
{Array.from({ length: 15 }).map((_, index) => (
<View key={index} style={styles.box}>
<Text>Elemento {index + 1}</Text>
<Text>Este es contenido importante que necesita ser visible</Text>
</View>
))}
</>
);
return (
<View style={styles.container}>
<Button
title={showScrollView ? "Quitar ScrollView" : "Agregar ScrollView"}
onPress={() => setShowScrollView(!showScrollView)}
/>
<Text style={styles.status}>
Estado: {showScrollView ? "CON ScrollView ✅" : "SIN ScrollView ❌"}
</Text>
{/* DEMOSTRACIÓN VISUAL */}
<View style={styles.demoArea}>
{showScrollView ? (
<ScrollView style={styles.scrollContainer}>
<Content />
</ScrollView>
) : (
<View style={styles.noScrollContainer}>
<Content />
{/* ⚠️ Este contenido no será visible sin scroll! */}
</View>
)}
</View>
</View>
);
};
const styles = StyleSheet.create({
container: { flex: 1, padding: 20 },
status: { textAlign: 'center', marginVertical: 10, fontWeight: 'bold' },
demoArea: { flex: 1, borderWidth: 2, borderColor: '#ccc', marginTop: 20 },
scrollContainer: { flex: 1 },
noScrollContainer: { flex: 1, overflow: 'hidden' },
box: {
height: 100,
backgroundColor: '#e3f2fd',
margin: 10,
padding: 15,
borderRadius: 8,
justifyContent: 'center'
},
});
Resultado visual:
text
CON SCROLLVIEW: SIN SCROLLVIEW:
┌─────────────────┐ ┌─────────────────┐
│ Elemento 1 │ │ Elemento 1 │
│ Elemento 2 │ │ Elemento 2 │
│ Elemento 3 │ SCROLL │ Elemento 3 │ ❌ CORTADO
│ ↓↓↓ →│ ↓↓↓↓ →│ │ ❌ NO VISIBLE
│ Elemento 14 │ │ [CONTENIDO │
│ Elemento 15 │ │ OCULTO] │
└─────────────────┘ └─────────────────┘
🔄 Paso 3: ScrollView Horizontal
3.1 Ejemplo Básico Horizontal
javascript
const HorizontalScrollExample = () => {
return (
<View style={styles.container}>
<Text style={styles.title}>Galería Horizontal</Text>
<ScrollView
horizontal={true} // ¡ESTA PROPIEDAD LO HACE HORIZONTAL!
showsHorizontalScrollIndicator={true}
style={styles.horizontalScroll}
>
{['🔴', '🔵', '🟢', '🟡', '🟣', '🟠'].map((emoji, index) => (
<View key={index} style={styles.card}>
<Text style={styles.emoji}>{emoji}</Text>
<Text>Tarjeta {index + 1}</Text>
</View>
))}
</ScrollView>
</View>
);
};
3.2 Visualización del Comportamiento
text
SCROLL HORIZONTAL:
┌───────────────────────────────────────┐
│ → → → → → → → → → → → → → → → → → → → │
│ 🔴 Tarjeta 1 🔵 Tarjeta 2 🟢 Tarjeta 3
│ ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← │
└───────────────────────────────────────┘
SCROLL → CONTENIDO OCULTO A LA DERECHA
🎯 Paso 4: ScrollView Anidados (Horizontal y Vertical)
4.1 Ejemplo Completo como en el Tutorial
javascript
const NestedScrollViews = () => {
return (
<View style={styles.fullContainer}>
{/* SCROLL VERTICAL PRINCIPAL */}
<ScrollView style={styles.verticalScroll}>
<Text style={styles.header}>Contenido Principal</Text>
{/* SCROLL HORIZONTAL DENTRO DEL VERTICAL */}
<Text style={styles.subheader}>Sección Horizontal</Text>
<ScrollView
horizontal={true}
style={styles.nestedHorizontal}
showsHorizontalScrollIndicator={false}
>
{Array.from({ length: 8 }).map((_, index) => (
<View key={index} style={styles.horizontalItem}>
<Text>Item H {index + 1}</Text>
</View>
))}
</ScrollView>
{/* MÁS CONTENIDO VERTICAL */}
<Text style={styles.subheader}>Más Contenido Vertical</Text>
{Array.from({ length: 10 }).map((_, index) => (
<View key={index} style={styles.verticalItem}>
<Text>Elemento Vertical {index + 1}</Text>
<Text>Desplázate hacia abajo para ver más</Text>
</View>
))}
</ScrollView>
</View>
);
};
const styles = StyleSheet.create({
fullContainer: { flex: 1 },
verticalScroll: { flex: 1 },
header: { fontSize: 24, fontWeight: 'bold', margin: 20, textAlign: 'center' },
subheader: { fontSize: 18, fontWeight: '600', margin: 15, marginLeft: 10 },
nestedHorizontal: {
height: 150,
marginHorizontal: 10,
},
horizontalItem: {
width: 200,
height: 120,
backgroundColor: '#bbdefb',
margin: 10,
justifyContent: 'center',
alignItems: 'center',
borderRadius: 10,
},
verticalItem: {
height: 100,
backgroundColor: '#f3e5f5',
margin: 10,
padding: 15,
borderRadius: 8,
justifyContent: 'center',
},
});
4.2 Visualización del Anidamiento
text
┌─────────────────────────────────┐
│ CONTENIDO PRINCIPAL │
│ │
│ SECCIÓN HORIZONTAL → │
│ [Item H1] [Item H2] [Item H3] →│ ← SCROLL HORIZONTAL
│ │
│ MÁS CONTENIDO VERTICAL │
│ Elemento Vertical 1 │
│ Elemento Vertical 2 │
│ ↓↓↓ →│ ← SCROLL VERTICAL
│ Elemento Vertical 10 │
└─────────────────────────────────┘
🛠️ Paso 5: Propiedades Esenciales de ScrollView
5.1 Propiedades de Control
javascript
<ScrollView
// Dirección
horizontal={true} // false por defecto (vertical)
// Indicadores
showsVerticalScrollIndicator={true} // Indicador vertical
showsHorizontalScrollIndicator={false} // Ocultar horizontal
// Desplazamiento
pagingEnabled={false} // Si true, desplaza por páginas completas
scrollEnabled={true} // Habilitar/deshabilitar scroll
// Comportamiento
keyboardShouldPersistTaps="handled" // Manejo del teclado
keyboardDismissMode="on-drag" // Ocultar teclado al desplazar
// Estilos
contentContainerStyle={styles.content} // Estilo del contenido interno
style={styles.container} // Estilo del ScrollView
>
5.2 Ejemplo con Configuración Completa
javascript
const ConfigurableScrollView = () => {
return (
<ScrollView
// Configuración esencial
horizontal={false} // Vertical
showsVerticalScrollIndicator={true} // Mostrar barra
showsHorizontalScrollIndicator={false}// Ocultar barra horizontal
// Mejora de UX
keyboardShouldPersistTaps="handled" // Bueno para formularios
keyboardDismissMode="on-drag" // Esconde teclado al desplazar
// Performance
removeClippedSubviews={true} // Mejora rendimiento
// Estilos
style={styles.scrollView}
contentContainerStyle={styles.contentContainer}
// Eventos
onScroll={(event) => {
console.log('Posición Y:', event.nativeEvent.contentOffset.y);
}}
onScrollBeginDrag={() => console.log('Empezó a desplazar')}
onScrollEndDrag={() => console.log('Terminó de desplazar')}
>
{/* Contenido aquí */}
</ScrollView>
);
};
📝 Paso 6: Casos de Uso Comunes
6.1 Perfil de Usuario (Como en Apps Sociales)
javascript
const UserProfileScreen = () => {
return (
<ScrollView
contentContainerStyle={styles.profileContainer}
showsVerticalScrollIndicator={false}
>
{/* Header con foto */}
<View style={styles.profileHeader}>
<Image style={styles.profileImage} source={/* ... */} />
<Text style={styles.profileName}>Ana García</Text>
<Text style={styles.profileBio}>Desarrolladora React Native</Text>
</View>
{/* Estadísticas (Scroll Horizontal dentro) */}
<Text style={styles.sectionTitle}>Estadísticas</Text>
<ScrollView horizontal showsHorizontalScrollIndicator={false}>
<StatCard title="Publicaciones" value="156" />
<StatCard title="Seguidores" value="2.4K" />
<StatCard title="Siguiendo" value="348" />
</ScrollView>
{/* Publicaciones */}
<Text style={styles.sectionTitle}>Publicaciones Recientes</Text>
{posts.map((post, index) => (
<PostCard key={index} post={post} />
))}
{/* Más contenido... */}
</ScrollView>
);
};
6.2 Formulario Largo
javascript
const LongFormScreen = () => {
return (
<ScrollView
contentContainerStyle={styles.formContainer}
keyboardShouldPersistTaps="handled"
>
<Text style={styles.formTitle}>Formulario de Registro</Text>
<TextInput style={styles.input} placeholder="Nombre completo" />
<TextInput style={styles.input} placeholder="Email" />
<TextInput style={styles.input} placeholder="Teléfono" />
<TextInput style={styles.input} placeholder="Dirección" multiline />
{/* Muchos más campos... */}
<Button title="Enviar" onPress={() => {}} />
{/* Términos y condiciones al final */}
<Text style={styles.terms}>
Al enviar aceptas los términos y condiciones...
</Text>
</ScrollView>
);
};
⚠️ Paso 7: Errores Comunes y Soluciones
❌ Error: "Elementos no se muestran completamente"
javascript
// MAL: Falta altura definida
<ScrollView>
<View>
<Text>Contenido</Text>
</View>
</ScrollView>
// SOLUCIÓN: Asegurar altura o usar flexGrow
<ScrollView contentContainerStyle={{ flexGrow: 1 }}>
<View style={{ minHeight: 800 }}>
<Text>Contenido</Text>
</View>
</ScrollView>
❌ Error: "Dos ScrollView anidados causan conflicto"
javascript
// MAL: Anidamiento problemático
<ScrollView>
<ScrollView> {/* ❌ Esto no funciona bien */}
<Text>Contenido</Text>
</ScrollView>
</ScrollView>
// SOLUCIÓN: Un ScrollView con contenido mixto
<ScrollView>
<View style={{ height: 200 }}> {/* Contenedor para sección fija */}
<Text>Contenido que no necesita scroll interno</Text>
</View>
<ScrollView horizontal> {/* ✅ Scroll horizontal permitido */}
<Text>Contenido horizontal</Text>
</ScrollView>
</ScrollView>
❌ Error: "Performance pobre con muchos elementos"
Solución: Usa FlatList en lugar de ScrollView para listas largas
javascript
// Para 100+ elementos, usa:
import { FlatList } from 'react-native';
<FlatList
data={items}
renderItem={({ item }) => <ItemComponent item={item} />}
keyExtractor={item => item.id}
/>
🎯 Paso 8: Ejercicio Práctico
Ejercicio: Crear una Pantalla de Producto
Crea un componente que muestre:
✅ Imagen del producto con scroll horizontal para galería
✅ Información del producto con scroll vertical
✅ Sección de opiniones desplazable
✅ Productos relacionados en scroll horizontal
javascript
const ProductScreen = () => {
return (
<ScrollView>
{/* Galería de imágenes horizontal */}
<ScrollView horizontal pagingEnabled>
{/* Imágenes del producto */}
</ScrollView>
{/* Información del producto */}
<View>
<Text>Nombre del Producto</Text>
<Text>Descripción larga...</Text>
{/* Más info */}
</View>
{/* Opiniones */}
<View>
<Text>Opiniones de clientes</Text>
{/* Lista de opiniones */}
</View>
{/* Productos relacionados (horizontal) */}
<Text>Productos relacionados</Text>
<ScrollView horizontal>
{/* Cards de productos */}
</ScrollView>
</ScrollView>
);
};
📊 Resumen: ¿Cuándo usar ScrollView?
🔧 Consejos Profesionales
Siempre prueba en dispositivos reales, los emuladores pueden comportarse diferente
Usa showsVerticalScrollIndicator={false} para diseño más limpio
Para formularios, combina con KeyboardAvoidingView
Evita ScrollView anidados en la misma dirección
Considera el impacto en performance con contenido complejo
🎬 Próximo Tutorial
En el siguiente video aprenderemos:
Componente FlatList para listas eficientes
Virtualización de elementos
Pull to refresh nativo
Optimización de listas largas
✅ ¡Ahora entiendes perfectamente ScrollView! Recuerda: es tu mejor amigo para contenido estático, pero para listas dinámicas largas, FlatList es el camino a seguir. ¡A practicar
Comentarios
Publicar un comentario