26. Align Content en React Native
Objetivo:
Aprender a utilizar la propiedad alignContent en React Native para controlar la distribución de múltiples líneas dentro de contenedores flex cuando se usa flexWrap, y entender la diferencia entre alignItems y alignContent.
Contenido del tutorial:
1. Introducción: alignContent vs alignItems
Problema común:
Cuando usamos flexWrap: 'wrap' (múltiples líneas), alignItems solo afecta elementos dentro de cada línea, no la distribución de las líneas en el contenedor.
Solución:
alignContent: Controla cómo se distribuyen las líneas en el eje cruzado.
alignItems: Controla cómo se alinean los elementos dentro de cada línea.
2. Configuración inicial
Ejemplo base con flexWrap:
jsx
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
// Componente Box reutilizable
const Box = ({ color, texto }) => {
return (
<View style={[styles.boxSize, { backgroundColor: color }]}>
<Text style={styles.text}>{texto}</Text>
</View>
);
};
const App = () => {
return (
<View style={styles.container}>
<Box color={'#4A5568'} texto={1} />
<Box color={'#2D3748'} texto={2} />
<Box color={'#48BB78'} texto={3} />
<Box color={'#ED64A6'} texto={4} />
<Box color={'#4299E1'} texto={5} />
<Box color={'#F56565'} texto={6} />
<Box color={'#ED8936'} texto={7} />
<Box color={'#38B2AC'} texto={8} />
<Box color={'#975A16'} texto={9} />
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'row',
flexWrap: 'wrap', // ← Múltiples líneas
// alignItems: 'center', ← Solo afecta elementos dentro de cada línea
alignContent: 'center', // ← Afecta la distribución de las líneas
backgroundColor: '#F7FAFC',
padding: 10,
},
boxSize: {
width: 100,
height: 100,
margin: 5,
justifyContent: 'center',
alignItems: 'center',
borderRadius: 8,
},
text: {
fontSize: 30,
fontWeight: 'bold',
color: 'white',
},
});
export default App;
3. Valores de alignContent (con flexWrap: 'wrap')
1. stretch (VALOR POR DEFECTO)
jsx
alignContent: 'stretch'
Comportamiento: Estira las líneas para llenar el espacio disponible en el eje cruzado.
Condición: Las líneas no deben tener altura fija.
Visual:
text
[1][2][3] ← Líneas estiradas verticalmente
[4][5][6]
[7][8][9]
2. flex-start
jsx
alignContent: 'flex-start'
Comportamiento: Agrupa las líneas al inicio del contenedor.
Visual:
text
[1][2][3] ← Líneas pegadas arriba
[4][5][6]
[7][8][9]
(espacio vacío abajo)
3. center (MUY ÚTIL)
jsx
alignContent: 'center'
Comportamiento: Centra el bloque de líneas verticalmente.
Visual:
text
(espacio)
[1][2][3]
[4][5][6]
[7][8][9]
(espacio)
4. flex-end
jsx
alignContent: 'flex-end'
Comportamiento: Agrupa las líneas al final del contenedor.
Visual:
text
(espacio vacío arriba)
[1][2][3]
[4][5][6]
[7][8][9]
5. space-between
jsx
alignContent: 'space-between'
Comportamiento: Distribuye líneas con espacio uniforme entre ellas, sin espacio en los extremos.
Visual:
text
[1][2][3]
(espacio)
[4][5][6]
(espacio)
[7][8][9]
6. space-around
jsx
alignContent: 'space-around'
Comportamiento: Distribuye líneas con espacio uniforme alrededor de cada línea.
Característica: El espacio en los extremos es la mitad del espacio entre líneas.
Visual:
text
(medio espacio)
[1][2][3]
(espacio completo)
[4][5][6]
(espacio completo)
[7][8][9]
(medio espacio)
7. space-evenly
jsx
alignContent: 'space-evenly'
Comportamiento: Distribuye líneas con espacio totalmente uniforme entre todas.
Visual:
text
(espacio)
[1][2][3]
(espacio)
[4][5][6]
(espacio)
[7][8][9]
(espacio)
4. Diferencia clara: alignItems vs alignContent
Ejemplo con alignItems: 'flex-end':
jsx
container: {
flex: 1,
flexDirection: 'row',
flexWrap: 'wrap',
alignItems: 'flex-end', // ← Solo esto
}
Resultado: Los elementos dentro de cada línea se alinean abajo, pero las líneas siguen pegadas arriba.
Ejemplo con alignContent: 'flex-end':
jsx
container: {
flex: 1,
flexDirection: 'row',
flexWrap: 'wrap',
alignContent: 'flex-end', // ← Solo esto
}
Resultado: El bloque completo de líneas se mueve hacia abajo.
Combinación de ambos:
jsx
container: {
flex: 1,
flexDirection: 'row',
flexWrap: 'wrap',
alignItems: 'center', // ← Centra elementos dentro de cada línea
alignContent: 'space-between', // ← Distribuye líneas verticalmente
}
5. Efecto de los márgenes en alignContent
Con márgenes:
jsx
boxSize: {
width: 100,
height: 100,
margin: 5, // ← Crea espacio entre cajas
}
Resultado: space-around y space-between distribuyen líneas considerando el espacio de los márgenes.
Sin márgenes (para stretch):
jsx
boxSize: {
width: 100,
height: 100,
// margin: 5, ← Sin margen para mejor stretch
}
Con alignContent: 'stretch': Las líneas ocupan todo el espacio disponible.
6. Código interactivo completo
jsx
import React, { useState } from 'react';
import { View, Text, StyleSheet, TouchableOpacity, ScrollView } from 'react-native';
// Componente Box
const Box = ({ color, texto }) => {
return (
<View style={[styles.boxSize, { backgroundColor: color }]}>
<Text style={styles.text}>{texto}</Text>
</View>
);
};
const App = () => {
const [alignContentValue, setAlignContentValue] = useState('center');
const [alignItemsValue, setAlignItemsValue] = useState('center');
const [hasMargin, setHasMargin] = useState(true);
const boxes = [
{ color: '#4A5568', texto: 1 },
{ color: '#2D3748', texto: 2 },
{ color: '#48BB78', texto: 3 },
{ color: '#ED64A6', texto: 4 },
{ color: '#4299E1', texto: 5 },
{ color: '#F56565', texto: 6 },
{ color: '#ED8936', texto: 7 },
{ color: '#38B2AC', texto: 8 },
{ color: '#975A16', texto: 9 },
{ color: '#805AD5', texto: 10 },
{ color: '#D69E2E', texto: 11 },
];
const alignContentOptions = [
'stretch',
'flex-start',
'center',
'flex-end',
'space-between',
'space-around',
'space-evenly',
];
const alignItemsOptions = [
'stretch',
'flex-start',
'center',
'flex-end',
'baseline',
];
return (
<View style={styles.main}>
{/* Controles */}
<View style={styles.controls}>
<Text style={styles.title}>alignContent (controla LÍNEAS):</Text>
<ScrollView horizontal showsHorizontalScrollIndicator={false}>
{alignContentOptions.map((option) => (
<TouchableOpacity
key={option}
style={[
styles.controlButton,
alignContentValue === option && styles.selectedButton,
]}
onPress={() => setAlignContentValue(option)}
>
<Text style={styles.controlText}>{option}</Text>
</TouchableOpacity>
))}
</ScrollView>
<Text style={styles.title}>alignItems (controla ELEMENTOS en cada línea):</Text>
<ScrollView horizontal showsHorizontalScrollIndicator={false}>
{alignItemsOptions.map((option) => (
<TouchableOpacity
key={option}
style={[
styles.controlButton,
alignItemsValue === option && styles.selectedButton,
]}
onPress={() => setAlignItemsValue(option)}
>
<Text style={styles.controlText}>{option}</Text>
</TouchableOpacity>
))}
</ScrollView>
<TouchableOpacity
style={[
styles.marginButton,
!hasMargin && styles.selectedButton,
]}
onPress={() => setHasMargin(!hasMargin)}
>
<Text style={styles.controlText}>
{hasMargin ? 'Con márgenes (m:5)' : 'Sin márgenes'}
</Text>
</TouchableOpacity>
</View>
{/* Información */}
<View style={styles.infoBox}>
<Text style={styles.infoText}>
📊 <Text style={{ fontWeight: 'bold' }}>alignContent:</Text> '{alignContentValue}'
{' | '}
<Text style={{ fontWeight: 'bold' }}>alignItems:</Text> '{alignItemsValue}'
</Text>
<Text style={styles.infoSubtext}>
• alignContent distribuye líneas • alignItems alinea elementos dentro de cada línea
</Text>
</View>
{/* Contenedor principal */}
<ScrollView style={styles.scrollView}>
<View style={[
styles.container,
{
alignContent: alignContentValue,
alignItems: alignItemsValue,
}
]}>
{boxes.map((box, index) => (
<Box
key={index}
color={box.color}
texto={box.texto}
/>
))}
</View>
</ScrollView>
{/* Explicación visual */}
<View style={styles.explanation}>
<Text style={styles.explanationTitle}>🎯 Diferencia clave:</Text>
<View style={styles.example}>
<View style={styles.exampleContainer}>
<Text style={styles.exampleTitle}>alignItems: 'center'</Text>
<Text style={styles.exampleText}>
Centra elementos DENTRO de cada línea
</Text>
<View style={styles.visualExample}>
<View style={styles.line}>
<View style={[styles.smallBox, { alignSelf: 'center' }]} />
<View style={[styles.smallBox, { alignSelf: 'center' }]} />
</View>
<View style={styles.line}>
<View style={[styles.smallBox, { alignSelf: 'center' }]} />
<View style={[styles.smallBox, { alignSelf: 'center' }]} />
</View>
</View>
</View>
<View style={styles.exampleContainer}>
<Text style={styles.exampleTitle}>alignContent: 'center'</Text>
<Text style={styles.exampleText}>
Centra el BLOQUE de líneas en el contenedor
</Text>
<View style={styles.visualExample}>
<View style={[styles.lineBlock, { alignSelf: 'center' }]}>
<View style={styles.line}>
<View style={styles.smallBox} />
<View style={styles.smallBox} />
</View>
<View style={styles.line}>
<View style={styles.smallBox} />
<View style={styles.smallBox} />
</View>
</View>
</View>
</View>
</View>
</View>
</View>
);
};
const styles = StyleSheet.create({
main: {
flex: 1,
paddingTop: 50,
backgroundColor: '#fff',
},
controls: {
padding: 15,
backgroundColor: '#f8f9fa',
borderBottomWidth: 1,
borderBottomColor: '#dee2e6',
},
title: {
fontSize: 12,
fontWeight: 'bold',
marginTop: 10,
marginBottom: 5,
color: '#495057',
},
controlButton: {
paddingVertical: 6,
paddingHorizontal: 10,
marginRight: 8,
backgroundColor: '#e9ecef',
borderRadius: 6,
minWidth: 80,
alignItems: 'center',
},
marginButton: {
paddingVertical: 10,
marginTop: 10,
backgroundColor: '#e9ecef',
borderRadius: 6,
alignItems: 'center',
},
selectedButton: {
backgroundColor: '#4D96FF',
},
controlText: {
color: '#333',
fontWeight: 'bold',
fontSize: 11,
},
infoBox: {
backgroundColor: '#E7F5FF',
padding: 12,
marginHorizontal: 15,
marginTop: 15,
borderRadius: 8,
borderWidth: 1,
borderColor: '#A5D8FF',
},
infoText: {
fontSize: 13,
color: '#1864AB',
fontWeight: '600',
},
infoSubtext: {
fontSize: 11,
color: '#364FC7',
marginTop: 4,
},
scrollView: {
flex: 1,
},
container: {
flex: 1,
flexDirection: 'row',
flexWrap: 'wrap',
minHeight: 400,
padding: 15,
backgroundColor: '#F7FAFC',
borderWidth: 2,
borderColor: '#E2E8F0',
margin: 15,
borderRadius: 10,
},
boxSize: {
width: 100,
height: 100,
margin: (props) => props.hasMargin ? 5 : 0,
justifyContent: 'center',
alignItems: 'center',
borderRadius: 8,
elevation: 2,
shadowColor: '#000',
shadowOffset: { width: 0, height: 1 },
shadowOpacity: 0.2,
shadowRadius: 2,
},
text: {
fontSize: 28,
fontWeight: 'bold',
color: 'white',
},
explanation: {
backgroundColor: '#F8F9FA',
margin: 15,
padding: 15,
borderRadius: 8,
borderWidth: 1,
borderColor: '#DEE2E6',
},
explanationTitle: {
fontSize: 14,
fontWeight: 'bold',
color: '#495057',
marginBottom: 10,
},
example: {
flexDirection: 'row',
justifyContent: 'space-between',
},
exampleContainer: {
flex: 1,
padding: 10,
backgroundColor: '#fff',
borderRadius: 6,
marginHorizontal: 5,
borderWidth: 1,
borderColor: '#E9ECEF',
},
exampleTitle: {
fontSize: 12,
fontWeight: 'bold',
color: '#4D96FF',
marginBottom: 5,
},
exampleText: {
fontSize: 10,
color: '#6C757D',
marginBottom: 10,
},
visualExample: {
height: 80,
justifyContent: 'center',
},
line: {
flexDirection: 'row',
justifyContent: 'center',
marginVertical: 5,
},
lineBlock: {
justifyContent: 'center',
},
smallBox: {
width: 20,
height: 20,
backgroundColor: '#4D96FF',
marginHorizontal: 5,
borderRadius: 3,
},
});
export default App;
7. Casos de uso prácticos
Galería centrada verticalmente:
jsx
container: {
flexDirection: 'row',
flexWrap: 'wrap',
alignContent: 'center', // ← Centra el grupo de líneas
justifyContent: 'space-around',
}
Formulario con campos distribuidos uniformemente:
jsx
container: {
flexDirection: 'row',
flexWrap: 'wrap',
alignContent: 'space-between', // ← Espacio uniforme entre filas
alignItems: 'stretch', // ← Campos ocupan altura completa
}
Dashboard con widgets:
jsx
container: {
flexDirection: 'row',
flexWrap: 'wrap',
alignContent: 'space-around', // ← Espacio alrededor de cada fila
justifyContent: 'center',
}
8. Reglas importantes
flexWrap requerido: alignContent solo funciona si flexWrap es 'wrap' o 'wrap-reverse'.
Múltiples líneas: Necesitas suficientes elementos para crear al menos 2 líneas.
Altura del contenedor: Debe tener altura definida o flex: 1 para ver efectos.
Combinación con justifyContent: Controla eje principal (horizontal) mientras alignContent controla eje cruzado (vertical).
Conclusión:
alignContent es esencial cuando trabajas con múltiples líneas de elementos flexibles. Recuerda:
✅ Solo funciona con flexWrap: 'wrap'
✅ Controla distribución de LÍNEAS (no elementos individuales)
✅ Complémenta alignItems que controla elementos dentro de cada línea
✅ Valores similares a justifyContent pero para el eje cruzado
✅ Esencial para grids y galerías bien alineadas
Próximo paso: Aprenderemos sobre flexBasis, flexGrow, y flexShrink para control avanzado de dimensiones flexibles.
💡 Consejo profesional: Para layouts complejos con múltiples filas, primero define flexWrap: 'wrap', luego ajusta alignContent para la distribución vertical, y finalmente usa alignItems para alineación horizontal dentro de cada fila
Comentarios
Publicar un comentario