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:

  1. ✅ Imagen del producto con scroll horizontal para galería

  2. ✅ Información del producto con scroll vertical

  3. ✅ Sección de opiniones desplazable

  4. ✅ 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?

Escenario

¿Usar ScrollView?

Alternativa

Formulario con 10 campos

✅ Sí


Lista de 5-20 elementos

✅ Sí


Lista de 100+ elementos

❌ No

FlatList

Galería de imágenes

✅ Sí (horizontal)


Perfil de usuario

✅ Sí


Feed infinito

❌ No

FlatList

Chat con mensajes

❌ No

FlatList invertido


🔧 Consejos Profesionales

  1. Siempre prueba en dispositivos reales, los emuladores pueden comportarse diferente

  2. Usa showsVerticalScrollIndicator={false} para diseño más limpio

  3. Para formularios, combina con KeyboardAvoidingView

  4. Evita ScrollView anidados en la misma dirección

  5. 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

Entradas más populares de este blog

18. Visualizar nuestros componentes limpios con StyleSheet

15. Componente Image

Tema: 23. Justify Content en Flexbox para Column (Columna) en React Nativ