12. Componente View

 

Tutorial: Componente View en React Native

📱 Parte 12: Componente View - El Contenedor Fundamental

🎯 Objetivo:

Aprender a usar el componente View de React Native como contenedor principal, entender su comportamiento y aplicar estilos para crear layouts básicos.


📸 Analizando el Ejemplo de la Imagen

Observando el código de la imagen:

javascript

import React from 'react';

import { View } from 'react-native';


const App = () => {

  return (

    <View> {/* Contenedor padre */}

      <View style={{backgroundColor: 'green', width: 150, height: 150}} />

      <View style={{backgroundColor: 'black', width: 150, height: 150}} />

      <View style={{backgroundColor: 'gray', width: 150, height: 150}} />

    </View>

  );

};


export default App;

Resultado visual esperado:

text

┌─────────────────────────────────┐

│    ┌─────────────┐              │

│    │    VERDE    │              │

│    │             │              │

│    └─────────────┘              │

│    ┌─────────────┐              │

│    │    NEGRO    │              │

│    │             │              │

│    └─────────────┘              │

│    ┌─────────────┐              │

│    │    GRIS     │              │

│    │             │              │

│    └─────────────┘              │

└─────────────────────────────────┘


🚀 Paso 1: ¿Qué es el Componente View?

View es el contenedor fundamental en React Native, equivalente a <div> en HTML. Es el bloque de construcción básico para crear interfaces.

1.1 Importación Básica

javascript

import React from 'react';

import { View } from 'react-native'; // ¡IMPORTANTE importar View!


📦 Paso 2: Creando Views Básicos

2.1 View Simple

javascript

const ViewBasico = () => {

  return (

    <View>

      {/* Este View no muestra nada visible */}

    </View>

  );

};

2.2 View con Estilos (Como en el Ejemplo)

javascript

const ViewConEstilos = () => {

  return (

    <View style={{ 

      backgroundColor: 'blue', 

      width: 200, 

      height: 200,

      margin: 20 

    }}>

      {/* Contenido del View */}

    </View>

  );

};

2.3 DEMOSTRACIÓN: Views Anidados

javascript

const ViewsAnidados = () => {

  return (

    {/* View contenedor principal */}

    <View style={styles.contenedorPrincipal}>

      

      {/* View hijo 1 */}

      <View style={styles.viewHijo1}>

        <Text>Hijo 1</Text>

      </View>

      

      {/* View hijo 2 */}

      <View style={styles.viewHijo2}>

        {/* View nieto dentro del hijo 2 */}

        <View style={styles.viewNieto}>

          <Text>Nieto</Text>

        </View>

      </View>

      

    </View>

  );

};


const styles = StyleSheet.create({

  contenedorPrincipal: {

    flex: 1,

    backgroundColor: '#f0f0f0',

    padding: 20,

  },

  viewHijo1: {

    backgroundColor: 'red',

    height: 100,

    justifyContent: 'center',

    alignItems: 'center',

    marginBottom: 10,

  },

  viewHijo2: {

    backgroundColor: 'blue',

    height: 200,

    padding: 20,

  },

  viewNieto: {

    backgroundColor: 'yellow',

    height: 100,

    justifyContent: 'center',

    alignItems: 'center',

  },

});


🎨 Paso 3: Propiedades Clave del Componente View

3.1 Propiedades de Estilo Esenciales

javascript

<View

  style={{

    // Tamaño

    width: 100,           // Ancho en puntos

    height: 100,          // Alto en puntos

    minWidth: 50,         // Ancho mínimo

    minHeight: 50,        // Alto mínimo

    maxWidth: 200,        // Ancho máximo

    maxHeight: 200,       // Alto máximo

    

    // Colores y fondos

    backgroundColor: 'red', // Color de fondo

    opacity: 0.8,           // Transparencia (0 a 1)

    

    // Bordes

    borderWidth: 2,         // Grosor del borde

    borderColor: 'black',   // Color del borde

    borderRadius: 10,       // Bordes redondeados

    borderTopWidth: 5,      // Borde superior específico

    

    // Espaciado

    margin: 10,            // Margen exterior

    marginTop: 5,          // Margen superior específico

    padding: 15,           // Relleno interior

    paddingLeft: 20,       // Relleno izquierdo específico

    

    // Posicionamiento

    position: 'relative',  // 'relative' o 'absolute'

    top: 10,               // Desde arriba (absolute)

    left: 20,              // Desde izquierda (absolute)

    zIndex: 1,             // Nivel de apilamiento

    

    // Sombra (iOS)

    shadowColor: '#000',

    shadowOffset: { width: 0, height: 2 },

    shadowOpacity: 0.25,

    shadowRadius: 3.84,

    

    // Elevación (Android)

    elevation: 5,

  }}

>

3.2 Ejemplo Completo con Todas las Propiedades

javascript

const ViewCompleto = () => {

  return (

    <View style={styles.contenedor}>

      {/* View con sombra y bordes redondeados */}

      <View style={styles.tarjeta}>

        <Text style={styles.textoTarjeta}>Tarjeta con estilo</Text>

      </View>

      

      {/* View con posición absoluta */}

      <View style={styles.badge}>

        <Text style={styles.textoBadge}>Nuevo!</Text>

      </View>

      

      {/* View transparente */}

      <View style={styles.overlay}>

        <Text>Contenido semitransparente</Text>

      </View>

    </View>

  );

};


const styles = StyleSheet.create({

  contenedor: {

    flex: 1,

    backgroundColor: '#f5f5f5',

    padding: 20,

  },

  tarjeta: {

    width: 200,

    height: 150,

    backgroundColor: 'white',

    borderRadius: 15,

    padding: 20,

    justifyContent: 'center',

    alignItems: 'center',

    

    // Sombra para iOS

    shadowColor: '#000',

    shadowOffset: {

      width: 0,

      height: 2,

    },

    shadowOpacity: 0.25,

    shadowRadius: 3.84,

    

    // Elevación para Android

    elevation: 5,

    

    // Borde

    borderWidth: 1,

    borderColor: '#e0e0e0',

  },

  badge: {

    position: 'absolute',

    top: 40,

    right: 40,

    backgroundColor: 'red',

    paddingHorizontal: 10,

    paddingVertical: 5,

    borderRadius: 12,

  },

  overlay: {

    position: 'absolute',

    bottom: 0,

    left: 0,

    right: 0,

    backgroundColor: 'rgba(0, 0, 0, 0.5)',

    padding: 20,

  },

  textoTarjeta: {

    fontSize: 18,

    fontWeight: 'bold',

  },

  textoBadge: {

    color: 'white',

    fontWeight: 'bold',

  },

});


🔄 Paso 4: Views Anidados - Jerarquía y Estructura

4.1 Ejemplo Práctico: Tarjeta de Producto

javascript

const ProductCard = () => {

  return (

    {/* View principal de la tarjeta */}

    <View style={styles.productCard}>

      

      {/* View para la imagen del producto */}

      <View style={styles.imageContainer}>

        <View style={styles.imagePlaceholder} />

        {/* Aquí iría un componente Image */}

      </View>

      

      {/* View para la información del producto */}

      <View style={styles.infoContainer}>

        

        {/* View para el título y precio */}

        <View style={styles.titleRow}>

          <Text style={styles.productTitle}>Producto Ejemplo</Text>

          <Text style={styles.productPrice}>$29.99</Text>

        </View>

        

        {/* View para la descripción */}

        <View style={styles.descriptionContainer}>

          <Text>Descripción del producto...</Text>

        </View>

        

        {/* View para los botones */}

        <View style={styles.buttonsContainer}>

          <View style={styles.button}>

            <Text style={styles.buttonText}>Comprar</Text>

          </View>

          <View style={[styles.button, styles.secondaryButton]}>

            <Text style={styles.buttonText}>Guardar</Text>

          </View>

        </View>

        

      </View>

      

    </View>

  );

};


const styles = StyleSheet.create({

  productCard: {

    backgroundColor: 'white',

    borderRadius: 10,

    margin: 10,

    padding: 15,

    shadowColor: '#000',

    shadowOffset: { width: 0, height: 2 },

    shadowOpacity: 0.1,

    shadowRadius: 4,

    elevation: 3,

  },

  imageContainer: {

    height: 150,

    backgroundColor: '#f0f0f0',

    borderRadius: 8,

    marginBottom: 15,

    justifyContent: 'center',

    alignItems: 'center',

  },

  imagePlaceholder: {

    width: 100,

    height: 100,

    backgroundColor: '#ccc',

  },

  infoContainer: {

    // El contenido se organiza automáticamente

  },

  titleRow: {

    flexDirection: 'row',

    justifyContent: 'space-between',

    alignItems: 'center',

    marginBottom: 10,

  },

  productTitle: {

    fontSize: 18,

    fontWeight: 'bold',

    flex: 1,

  },

  productPrice: {

    fontSize: 20,

    fontWeight: 'bold',

    color: '#2e7d32',

  },

  descriptionContainer: {

    marginBottom: 15,

  },

  buttonsContainer: {

    flexDirection: 'row',

    justifyContent: 'space-between',

  },

  button: {

    backgroundColor: '#2196f3',

    paddingVertical: 10,

    paddingHorizontal: 20,

    borderRadius: 5,

    flex: 1,

    marginHorizontal: 5,

    alignItems: 'center',

  },

  secondaryButton: {

    backgroundColor: '#f5f5f5',

  },

  buttonText: {

    color: 'white',

    fontWeight: 'bold',

  },

});


🎯 Paso 5: Flexbox con Views (Diseño Responsivo)

5.1 Conceptos Básicos de Flexbox en View

javascript

const FlexboxBasico = () => {

  return (

    <View style={styles.flexContainer}>

      {/* View con flex: 1 ocupa espacio disponible */}

      <View style={[styles.box, { backgroundColor: 'red', flex: 1 }]}>

        <Text>Flex: 1</Text>

      </View>

      

      {/* View con flex: 2 ocupa el doble que el anterior */}

      <View style={[styles.box, { backgroundColor: 'blue', flex: 2 }]}>

        <Text>Flex: 2</Text>

      </View>

      

      {/* View con flex: 1 ocupa igual que el primero */}

      <View style={[styles.box, { backgroundColor: 'green', flex: 1 }]}>

        <Text>Flex: 1</Text>

      </View>

    </View>

  );

};


const styles = StyleSheet.create({

  flexContainer: {

    flex: 1,

    flexDirection: 'row', // 'row' | 'column'

    justifyContent: 'space-between', // Alineación principal

    alignItems: 'center', // Alineación secundaria

  },

  box: {

    justifyContent: 'center',

    alignItems: 'center',

  },

});

5.2 Ejercicio: Layout de Columnas

javascript

const ColumnLayout = () => {

  return (

    <View style={styles.container}>

      {/* Header */}

      <View style={styles.header}>

        <Text style={styles.headerText}>Mi Aplicación</Text>

      </View>

      

      {/* Contenido principal en fila */}

      <View style={styles.mainContent}>

        {/* Sidebar */}

        <View style={styles.sidebar}>

          <Text>Menú 1</Text>

          <Text>Menú 2</Text>

          <Text>Menú 3</Text>

        </View>

        

        {/* Contenido */}

        <View style={styles.content}>

          <Text>Contenido principal aquí</Text>

        </View>

        

        {/* Sidebar derecha */}

        <View style={styles.sidebar}>

          <Text>Widget 1</Text>

          <Text>Widget 2</Text>

        </View>

      </View>

      

      {/* Footer */}

      <View style={styles.footer}>

        <Text>© 2024 Mi App</Text>

      </View>

    </View>

  );

};


const styles = StyleSheet.create({

  container: {

    flex: 1,

  },

  header: {

    height: 60,

    backgroundColor: '#6200ee',

    justifyContent: 'center',

    alignItems: 'center',

  },

  headerText: {

    color: 'white',

    fontSize: 20,

    fontWeight: 'bold',

  },

  mainContent: {

    flex: 1,

    flexDirection: 'row',

  },

  sidebar: {

    width: 100,

    backgroundColor: '#f5f5f5',

    padding: 10,

  },

  content: {

    flex: 1,

    backgroundColor: 'white',

    padding: 20,

  },

  footer: {

    height: 50,

    backgroundColor: '#333',

    justifyContent: 'center',

    alignItems: 'center',

  },

});


⚡ Paso 6: Eventos y Gestos en View

6.1 View como Botón (Pressable)

javascript

const PressableView = () => {

  const [pressed, setPressed] = useState(false);


  return (

    <View

      style={[

        styles.buttonView,

        pressed && styles.buttonPressed

      ]}

      onTouchStart={() => setPressed(true)}

      onTouchEnd={() => {

        setPressed(false);

        console.log('View presionado!');

      }}

      onLongPress={() => alert('Presión larga!')}

    >

      <Text>Presióname</Text>

    </View>

  );

};


const styles = StyleSheet.create({

  buttonView: {

    width: 200,

    height: 50,

    backgroundColor: '#007AFF',

    justifyContent: 'center',

    alignItems: 'center',

    borderRadius: 8,

  },

  buttonPressed: {

    backgroundColor: '#0056CC',

    transform: [{ scale: 0.95 }],

  },

});

6.2 View con Múltiples Eventos

javascript

const InteractiveView = () => {

  const [touchCount, setTouchCount] = useState(0);


  return (

    <View

      style={styles.interactiveBox}

      onTouchStart={() => console.log('Touch started')}

      onTouchMove={(event) => {

        const { locationX, locationY } = event.nativeEvent;

        console.log(`Moviendo en: ${locationX}, ${locationY}`);

      }}

      onTouchEnd={() => {

        setTouchCount(prev => prev + 1);

        console.log('Touch ended');

      }}

    >

      <Text>Toques: {touchCount}</Text>

      <Text>¡Tócame!</Text>

    </View>

  );

};


🛠️ Paso 7: Ejercicio Práctico - Creando un Layout Completo

Objetivo: Crear una pantalla de perfil usando solo Views

javascript

const ProfileScreen = () => {

  return (

    <View style={styles.container}>

      {/* Header */}

      <View style={styles.header}>

        <View style={styles.avatarContainer}>

          <View style={styles.avatar} />

        </View>

        <View style={styles.userInfo}>

          <Text style={styles.userName}>Juan Pérez</Text>

          <Text style={styles.userTitle}>Desarrollador React Native</Text>

        </View>

      </View>

      

      {/* Stats */}

      <View style={styles.statsContainer}>

        <View style={styles.statItem}>

          <Text style={styles.statNumber}>156</Text>

          <Text style={styles.statLabel}>Publicaciones</Text>

        </View>

        <View style={styles.statDivider} />

        <View style={styles.statItem}>

          <Text style={styles.statNumber}>2.4K</Text>

          <Text style={styles.statLabel}>Seguidores</Text>

        </View>

        <View style={styles.statDivider} />

        <View style={styles.statItem}>

          <Text style={styles.statNumber}>348</Text>

          <Text style={styles.statLabel}>Siguiendo</Text>

        </View>

      </View>

      

      {/* Bio */}

      <View style={styles.bioContainer}>

        <Text>Apasionado por el desarrollo móvil y la tecnología.</Text>

      </View>

      

      {/* Action Buttons */}

      <View style={styles.actionsContainer}>

        <View style={styles.primaryButton}>

          <Text style={styles.primaryButtonText}>Seguir</Text>

        </View>

        <View style={styles.secondaryButton}>

          <Text style={styles.secondaryButtonText}>Mensaje</Text>

        </View>

      </View>

      

      {/* Posts Grid */}

      <View style={styles.postsGrid}>

        {[1, 2, 3, 4, 5, 6].map((item) => (

          <View key={item} style={styles.postItem} />

        ))}

      </View>

    </View>

  );

};


const styles = StyleSheet.create({

  container: { flex: 1, backgroundColor: '#fff' },

  header: { 

    flexDirection: 'row', 

    padding: 20, 

    alignItems: 'center' 

  },

  avatarContainer: { 

    marginRight: 15 

  },

  avatar: { 

    width: 80, 

    height: 80, 

    borderRadius: 40, 

    backgroundColor: '#ccc' 

  },

  userInfo: { 

    flex: 1 

  },

  userName: { 

    fontSize: 22, 

    fontWeight: 'bold' 

  },

  userTitle: { 

    fontSize: 16, 

    color: '#666' 

  },

  statsContainer: { 

    flexDirection: 'row', 

    paddingVertical: 20, 

    borderTopWidth: 1, 

    borderBottomWidth: 1, 

    borderColor: '#eee' 

  },

  statItem: { 

    flex: 1, 

    alignItems: 'center' 

  },

  statNumber: { 

    fontSize: 20, 

    fontWeight: 'bold' 

  },

  statLabel: { 

    fontSize: 14, 

    color: '#666' 

  },

  statDivider: { 

    width: 1, 

    backgroundColor: '#eee' 

  },

  bioContainer: { 

    padding: 20 

  },

  actionsContainer: { 

    flexDirection: 'row', 

    paddingHorizontal: 20, 

    marginBottom: 20 

  },

  primaryButton: { 

    flex: 2, 

    backgroundColor: '#3897f0', 

    padding: 12, 

    borderRadius: 5, 

    alignItems: 'center', 

    marginRight: 10 

  },

  primaryButtonText: { 

    color: 'white', 

    fontWeight: 'bold' 

  },

  secondaryButton: { 

    flex: 1, 

    backgroundColor: '#f0f0f0', 

    padding: 12, 

    borderRadius: 5, 

    alignItems: 'center' 

  },

  secondaryButtonText: { 

    fontWeight: 'bold' 

  },

  postsGrid: { 

    flexDirection: 'row', 

    flexWrap: 'wrap', 

    padding: 2 

  },

  postItem: { 

    width: '33.33%', 

    aspectRatio: 1, 

    backgroundColor: '#f0f0f0', 

    borderWidth: 1, 

    borderColor: '#fff' 

  },

});


📋 Paso 8: Mejores Prácticas con View

8.1 Consejos para un Código Limpio

  1. Evita Views innecesarios - No anides más de lo necesario

  2. Usa StyleSheet.create() en lugar de estilos inline

  3. Nombra tus estilos descriptivamente

  4. Reutiliza componentes en lugar de copiar Views

  5. Mantén la jerarquía plana cuando sea posible

8.2 Ejemplo: Buenas vs Malas Prácticas

javascript

// ❌ MAL: Anidamiento excesivo y estilos inline

const MalEjemplo = () => (

  <View>

    <View>

      <View style={{backgroundColor: 'red', width: 100, height: 100}}>

        <Text>Hola</Text>

      </View>

    </View>

  </View>

);


// ✅ BIEN: Estructura plana y estilos separados

const BuenEjemplo = () => (

  <View style={styles.container}>

    <View style={styles.box}>

      <Text style={styles.text}>Hola</Text>

    </View>

  </View>

);


const styles = StyleSheet.create({

  container: { /* estilos */ },

  box: { 

    backgroundColor: 'red', 

    width: 100, 

    height: 100,

    justifyContent: 'center',

    alignItems: 'center'

  },

  text: { color: 'white' },

});


⚠️ Paso 9: Errores Comunes

❌ Error: "View no se muestra"

javascript

// MAL: Falta tamaño o color

<View>

  <Text>Contenido</Text>

</View>


// SOLUCIÓN: Agregar estilos visibles

<View style={{ backgroundColor: '#f0f0f0', padding: 20 }}>

  <Text>Contenido</Text>

</View>

❌ Error: "Views se solapan"

javascript

// SOLUCIÓN: Usar flexbox o dimensiones explícitas

<View style={{ flex: 1, flexDirection: 'row' }}>

  <View style={{ flex: 1, backgroundColor: 'red' }} />

  <View style={{ flex: 1, backgroundColor: 'blue' }} />

</View>


🎯 Resumen: ¿Cuándo usar View?

Propósito

Ejemplo

Contenedor principal

Pantallas, secciones

Agrupación de elementos

Formularios, listas

Creación de layouts

Grids, columnas, filas

Elementos visuales

Tarjetas, badges, separadores

Manejo de eventos

Botones personalizados, áreas táctiles


🎬 Próximo Tutorial

En el siguiente video aprenderemos:

  • Componente Text para mostrar contenido escrito

  • Estilización de texto con diferentes fuentes y tamaños

  • Texto enriquecido con múltiples estilos

  • Manipulación de texto en React Native


✅ ¡Ahora dominas el componente View! Es el bloque fundamental de todas las aplicaciones React Native. Recuerda: practica creando diferentes layouts y experimenta con las propiedades para entender completamente su poder


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