19. Creación de estilos

 

Tutorial: Creación de Estilos en React Native - Buenas Prácticas

En este tutorial aprenderás a crear y aplicar estilos en React Native de manera profesional, siguiendo las mejores prácticas recomendadas por la documentación oficial.


🎯 Objetivo del Tutorial

Aprender a crear hojas de estilos en React Native usando StyleSheet, entender las propiedades disponibles y organizar los estilos correctamente.


🎨 Paso 1: El Problema de los Estilos Inline

❌ Estilo INLINE (Mala práctica):

tsx

function MiComponente(): JSX.Element {

  return (

    <View

      style={{

        width: 50,

        height: 50,

        backgroundColor: 'red',

        margin: 10,

      }}

    />

  );

}

Problemas:

  1. Difícil de leer en componentes complejos

  2. Sin reutilización de estilos

  3. Sin validación en tiempo de desarrollo

  4. Sin optimización de performance

✅ Estilo con StyleSheet (Buena práctica):

tsx

import {StyleSheet, View} from 'react-native';


function MiComponente(): JSX.Element {

  return <View style={styles.container} />;

}


const styles = StyleSheet.create({

  container: {

    width: 50,

    height: 50,

    backgroundColor: 'red',

    margin: 10,

  },

});


📝 Paso 2: Crear Estilos con StyleSheet

Estructura básica:

tsx

// MiPrimerComponente.tsx

import React from 'react';

import {StyleSheet, View, ViewStyle} from 'react-native';


function MiPrimerComponente(): JSX.Element {

  return <View style={styles.mainComponent} />;

}


const styles = StyleSheet.create({

  mainComponent: {

    width: 50,

    height: 50,

    backgroundColor: 'red',

    borderRadius: 25,

    borderColor: 'green',

    borderWidth: 5,

  } as ViewStyle,

});


export default MiPrimerComponente;

Explicación del código:

  1. StyleSheet.create(): Método para crear estilos optimizados

  2. ViewStyle: Tipo TypeScript para validar propiedades

  3. Propiedades comunes:

    • width, height: Dimensiones

    • backgroundColor: Color de fondo

    • borderRadius: Radio de las esquinas

    • borderColor: Color del borde

    • borderWidth: Grosor del borde


🔍 Paso 3: Explorar ViewStyle y Propiedades Disponibles

Importar tipos:

tsx

import {ViewStyle} from 'react-native';

Ver propiedades disponibles (Ctrl+Click / Cmd+Click en ViewStyle):

typescript

interface ViewStyle extends FlexStyle, ShadowStyleIOS, TransformsStyle {

  // Colores y fondos

  backgroundColor?: string;

  opacity?: number;

  

  // Bordes

  borderWidth?: number;

  borderColor?: string;

  borderRadius?: number;

  borderTopWidth?: number;

  borderBottomWidth?: number;

  borderLeftWidth?: number;

  borderRightWidth?: number;

  

  // Posicionamiento

  position?: 'absolute' | 'relative';

  top?: number;

  bottom?: number;

  left?: number;

  right?: number;

  

  // Transformaciones

  transform?: Array<{

    perspective?: number;

    rotate?: string;

    rotateX?: string;

    rotateY?: string;

    scale?: number;

    scaleX?: number;

    scaleY?: number;

    translateX?: number;

    translateY?: number;

    skewX?: string;

    skewY?: string;

  }>;

}


📊 Paso 4: Categorías de Propiedades de Estilo

1. Dimensiones y Posición:

tsx

const styles = StyleSheet.create({

  container: {

    // Dimensiones

    width: 100,

    height: 100,

    minWidth: 50,

    maxHeight: 200,

    

    // Posición

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

    top: 10,

    left: 20,

    right: 30,

    bottom: 40,

    

    // Display

    display: 'flex', // por defecto en View

  },

});

2. Flexbox (Alineación y Distribución):

tsx

const styles = StyleSheet.create({

  container: {

    // Flex

    flex: 1,

    flexDirection: 'row', // 'column', 'row', 'column-reverse', 'row-reverse'

    flexWrap: 'wrap', // 'nowrap', 'wrap', 'wrap-reverse'

    

    // Alineación

    justifyContent: 'center', // 'flex-start', 'flex-end', 'center', 'space-between', 'space-around', 'space-evenly'

    alignItems: 'stretch', // 'flex-start', 'flex-end', 'center', 'baseline'

    alignContent: 'flex-start', // similar a justifyContent pero para múltiples líneas

    

    // Alineación individual

    alignSelf: 'center',

  },

});

3. Márgenes y Espaciado:

tsx

const styles = StyleSheet.create({

  container: {

    // Márgenes externos

    margin: 10, // todos los lados

    marginHorizontal: 20, // izquierda y derecha

    marginVertical: 15, // arriba y abajo

    marginTop: 5,

    marginBottom: 5,

    marginLeft: 5,

    marginRight: 5,

    

    // Padding interno

    padding: 10,

    paddingHorizontal: 20,

    paddingVertical: 15,

    paddingTop: 5,

    paddingBottom: 5,

    paddingLeft: 5,

    paddingRight: 5,

  },

});

4. Bordes:

tsx

const styles = StyleSheet.create({

  container: {

    // Bordes completos

    borderWidth: 2,

    borderColor: '#000000',

    borderRadius: 10,

    

    // Bordes individuales

    borderTopWidth: 1,

    borderTopColor: 'red',

    borderBottomWidth: 1,

    borderBottomColor: 'blue',

    borderLeftWidth: 1,

    borderLeftColor: 'green',

    borderRightWidth: 1,

    borderRightColor: 'yellow',

    

    // Bordes redondeados específicos

    borderTopLeftRadius: 20,

    borderTopRightRadius: 15,

    borderBottomLeftRadius: 10,

    borderBottomRightRadius: 5,

  },

});

5. Fondos y Sombras:

tsx

const styles = StyleSheet.create({

  container: {

    // Colores

    backgroundColor: '#FFFFFF',

    opacity: 0.8,

    

    // Sombras (iOS)

    shadowColor: '#000000',

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

    shadowOpacity: 0.25,

    shadowRadius: 3.84,

    

    // Elevación (Android)

    elevation: 5,

    

    // Overlay (solo iOS)

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

  },

});

6. Transformaciones:

tsx

const styles = StyleSheet.create({

  container: {

    // Rotación

    transform: [{rotate: '45deg'}],

    

    // Escala

    transform: [{scale: 1.5}],

    transform: [{scaleX: 2}, {scaleY: 0.5}],

    

    // Traslación

    transform: [{translateX: 50}, {translateY: -20}],

    

    // Combinaciones

    transform: [

      {rotate: '30deg'},

      {scale: 1.2},

      {translateX: 10},

    ],

    

    // Perspectiva (3D)

    transform: [{perspective: 1000}, {rotateY: '45deg'}],

  },

});


🎯 Paso 5: Crear un Círculo con Estilos

Ejemplo práctico: Componente circular

tsx

import React from 'react';

import {StyleSheet, View, ViewStyle} from 'react-native';


function Circulo(): JSX.Element {

  return <View style={styles.circulo} />;

}


const styles = StyleSheet.create({

  circulo: {

    // Para hacer un círculo, el ancho y alto deben ser iguales

    // y el borderRadius debe ser la mitad del ancho/alto

    width: 100,

    height: 100,

    backgroundColor: 'red',

    

    // Esto crea un círculo perfecto

    borderRadius: 50, // 100 / 2 = 50

    

    // Borde decorativo

    borderColor: 'green',

    borderWidth: 5,

    

    // Sombra

    shadowColor: '#000',

    shadowOffset: {

      width: 0,

      height: 4,

    },

    shadowOpacity: 0.3,

    shadowRadius: 4.65,

    elevation: 8,

    

    // Centrar si está dentro de un contenedor

    alignSelf: 'center',

    margin: 20,

  } as ViewStyle,

});


export default Circulo;

Círculo con props dinámicas:

tsx

interface CirculoProps {

  tamaño?: number;

  color?: string;

  colorBorde?: string;

  grosorBorde?: number;

}


function Circulo({

  tamaño = 100,

  color = 'red',

  colorBorde = 'green',

  grosorBorde = 5,

}: CirculoProps): JSX.Element {

  return (

    <View

      style={[

        styles.circuloBase,

        {

          width: tamaño,

          height: tamaño,

          borderRadius: tamaño / 2,

          backgroundColor: color,

          borderColor: colorBorde,

          borderWidth: grosorBorde,

        },

      ]}

    />

  );

}


const styles = StyleSheet.create({

  circuloBase: {

    alignSelf: 'center',

    margin: 10,

    shadowColor: '#000',

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

    shadowOpacity: 0.25,

    shadowRadius: 3.84,

    elevation: 5,

  },

});


📂 Paso 6: Organizar Estilos en Archivos Separados

Opción A: Estilos en el mismo archivo (Recomendado para componentes simples)

tsx

// MiComponente.tsx

import React from 'react';

import {StyleSheet, View} from 'react-native';


function MiComponente(): JSX.Element {

  return <View style={styles.container} />;

}


const styles = StyleSheet.create({

  container: {

    // estilos aquí

  },

});


export default MiComponente;

Opción B: Estilos en archivo separado (Recomendado para componentes complejos)

tsx

// MiComponente.styles.ts

import {StyleSheet} from 'react-native';


export default StyleSheet.create({

  container: {

    width: 100,

    height: 100,

    backgroundColor: 'blue',

  },

  texto: {

    fontSize: 16,

    color: 'white',

  },

});


// MiComponente.tsx

import React from 'react';

import {View, Text} from 'react-native';

import styles from './MiComponente.styles';


function MiComponente(): JSX.Element {

  return (

    <View style={styles.container}>

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

    </View>

  );

}


export default MiComponente;

Opción C: Múltiples archivos de estilos

bash

# Estructura de carpetas

MiComponente/

├── MiComponente.tsx

├── MiComponente.styles.ts

├── MiComponente.types.ts

└── index.ts


🎨 Paso 7: Combinar Múltiples Estilos

Usar array de estilos:

tsx

function MiComponente(): JSX.Element {

  return (

    <View style={[styles.base, styles.borde, styles.sombra]}>

      <Text style={[styles.textoBase, styles.textoGrande]}>

        Texto combinado

      </Text>

    </View>

  );

}


const styles = StyleSheet.create({

  base: {

    padding: 20,

    backgroundColor: 'white',

  },

  borde: {

    borderWidth: 1,

    borderColor: '#ccc',

    borderRadius: 8,

  },

  sombra: {

    shadowColor: '#000',

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

    shadowOpacity: 0.1,

    shadowRadius: 4,

    elevation: 3,

  },

  textoBase: {

    fontSize: 14,

    color: '#333',

  },

  textoGrande: {

    fontSize: 18,

    fontWeight: 'bold',

  },

});

Estilos condicionales:

tsx

interface BotonProps {

  primario?: boolean;

  deshabilitado?: boolean;

}


function Boton({primario = false, deshabilitado = false}: BotonProps): JSX.Element {

  return (

    <View

      style={[

        styles.boton,

        primario && styles.botonPrimario,

        deshabilitado && styles.botonDeshabilitado,

      ]}

    />

  );

}


const styles = StyleSheet.create({

  boton: {

    padding: 15,

    borderRadius: 8,

  },

  botonPrimario: {

    backgroundColor: '#007AFF',

  },

  botonDeshabilitado: {

    backgroundColor: '#CCCCCC',

    opacity: 0.6,

  },

});


🔧 Paso 8: Buenas Prácticas de Estilos

1. Usar constantes para valores repetidos:

tsx

const ESPACIADO = {

  pequeño: 8,

  medio: 16,

  grande: 24,

};


const COLORES = {

  primario: '#007AFF',

  secundario: '#5856D6',

  fondo: '#F2F2F7',

  texto: '#000000',

  textoSecundario: '#8E8E93',

};


const styles = StyleSheet.create({

  container: {

    padding: ESPACIADO.medio,

    backgroundColor: COLORES.fondo,

  },

  titulo: {

    fontSize: 24,

    color: COLORES.texto,

    marginBottom: ESPACIADO.pequeño,

  },

});

2. Crear estilos reutilizables:

tsx

// estilosComunes.ts

import {StyleSheet} from 'react-native';


export const sombra = {

  shadowColor: '#000',

  shadowOffset: {

    width: 0,

    height: 2,

  },

  shadowOpacity: 0.25,

  shadowRadius: 3.84,

  elevation: 5,

};


export const bordeRedondeado = {

  borderRadius: 8,

  borderWidth: 1,

  borderColor: '#E5E5EA',

};


// En tu componente

import {sombra, bordeRedondeado} from './estilosComunes';


const styles = StyleSheet.create({

  tarjeta: {

    ...sombra,

    ...bordeRedondeado,

    backgroundColor: 'white',

    padding: 16,

  },

});

3. Responsive con Dimensions:

tsx

import {Dimensions, StyleSheet} from 'react-native';


const {width, height} = Dimensions.get('window');


const styles = StyleSheet.create({

  container: {

    width: width * 0.9, // 90% del ancho de la pantalla

    maxWidth: 400, // Máximo 400px

    height: height * 0.3, // 30% del alto de la pantalla

  },

  imagen: {

    width: '100%', // 100% del contenedor padre

    aspectRatio: 16 / 9, // Mantener relación de aspecto

  },

});


🐛 Paso 9: Solución de Problemas Comunes

Error: "Property does not exist on type ViewStyle"

tsx

// ❌ INCORRECTO

const styles = StyleSheet.create({

  container: {

    color: 'red', // ❌ 'color' no existe en ViewStyle

  },

});


// ✅ CORRECTO - usar backgroundColor

const styles = StyleSheet.create({

  container: {

    backgroundColor: 'red', // ✅ Correcto

  },

});

Error: TypeScript - missing properties

tsx

// Agregar tipo ViewStyle

const styles = StyleSheet.create({

  container: {

    width: 100,

    height: 100,

    backgroundColor: 'red',

  } as ViewStyle, // ✅ Ayuda a TypeScript

});

Estilos que no se aplican

tsx

// Verificar:

// 1. Nombre correcto de la propiedad

// 2. Valor correcto (números sin comillas, strings con comillas)

// 3. Que el componente acepte la propiedad de estilo

// 4. No hay estilos en línea que sobrescriban


// ❌

style={{width: '100'}} // String en lugar de número


// ✅

style={{width: 100}} // Número correcto


🧪 Paso 10: Ejercicio Práctico - Tarjeta de Perfil

Crear una tarjeta de perfil con estilos:

tsx

// PerfilCard.tsx

import React from 'react';

import {View, Text, Image, StyleSheet} from 'react-native';


function PerfilCard(): JSX.Element {

  return (

    <View style={styles.tarjeta}>

      <Image

        source={{uri: 'https://via.placeholder.com/100'}}

        style={styles.avatar}

      />

      <View style={styles.contenido}>

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

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

        <Text style={styles.descripcion}>

          Apasionado por el desarrollo móvil y las buenas prácticas

        </Text>

        <View style={styles.etiquetas}>

          <Text style={styles.etiqueta}>React</Text>

          <Text style={styles.etiqueta}>TypeScript</Text>

          <Text style={styles.etiqueta}>Mobile</Text>

        </View>

      </View>

    </View>

  );

}


const styles = StyleSheet.create({

  tarjeta: {

    backgroundColor: '#FFFFFF',

    borderRadius: 16,

    padding: 20,

    margin: 16,

    shadowColor: '#000',

    shadowOffset: {

      width: 0,

      height: 4,

    },

    shadowOpacity: 0.1,

    shadowRadius: 12,

    elevation: 5,

    flexDirection: 'row',

    alignItems: 'flex-start',

  },

  avatar: {

    width: 80,

    height: 80,

    borderRadius: 40,

    marginRight: 16,

  },

  contenido: {

    flex: 1,

  },

  nombre: {

    fontSize: 20,

    fontWeight: 'bold',

    color: '#1D1D1F',

    marginBottom: 4,

  },

  titulo: {

    fontSize: 16,

    color: '#6E6E73',

    marginBottom: 8,

  },

  descripcion: {

    fontSize: 14,

    color: '#424245',

    lineHeight: 20,

    marginBottom: 12,

  },

  etiquetas: {

    flexDirection: 'row',

    flexWrap: 'wrap',

  },

  etiqueta: {

    backgroundColor: '#F2F2F7',

    paddingHorizontal: 12,

    paddingVertical: 6,

    borderRadius: 16,

    fontSize: 12,

    color: '#424245',

    marginRight: 8,

    marginBottom: 8,

  },

});


export default PerfilCard;


✅ Checklist de Estilos Correctos

  • Uso de StyleSheet.create() en lugar de estilos inline

  • Propiedades válidas para el tipo de componente

  • Nombres descriptivos para los estilos

  • Organización lógica de las propiedades

  • Reutilización de estilos comunes

  • Tipado TypeScript correcto (con as ViewStyle si es necesario)

  • Responsive design considerando diferentes tamaños de pantalla


🎉 ¡Felicidades!

Has aprendido a crear estilos profesionales en React Native. Ahora sabes:

✅ Crear hojas de estilos con StyleSheet
✅ Usar propiedades de ViewStyle correctamente
✅ Organizar estilos en archivos separados
✅ Combinar múltiples estilos
✅ Crear componentes visualmente atractivos
✅ Seguir buenas prácticas de diseño


📚 Recursos Adicionales


¡Excelente trabajo! Ahora tienes las herramientas para crear interfaces visualmente atractivas y bien estructuradas. Sigue practicando con diferentes componentes y estilos.


Comentarios

Entradas más populares de este blog

Guía Paso a Paso para Entender React Native (antes del Tutorial)

Tutorial: Aplicación React Native para Agregar Tareas - Minimalista

5. Vista Rapida: Estructura Projecto Base