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.

Propiedad

Nivel de control

Se usa con flexWrap

Ejemplo

alignItems

Elementos individuales

NO necesario

Centrar elementos dentro de su línea

alignContent

Líneas completas

SÍ necesario

Centrar múltiples filas en el contenedor


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

  1. flexWrap requerido: alignContent solo funciona si flexWrap es 'wrap' o 'wrap-reverse'.

  2. Múltiples líneas: Necesitas suficientes elementos para crear al menos 2 líneas.

  3. Altura del contenedor: Debe tener altura definida o flex: 1 para ver efectos.

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

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