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:
Difícil de leer en componentes complejos
Sin reutilización de estilos
Sin validación en tiempo de desarrollo
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:
StyleSheet.create(): Método para crear estilos optimizados
ViewStyle: Tipo TypeScript para validar propiedades
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
Publicar un comentario