24. Align Items en React Native Flexbox

 

Objetivo:

Comprender y aplicar la propiedad alignItems en React Native para controlar la alineación de elementos en el eje cruzado (perpendicular al eje principal) dentro de contenedores flex.


Contenido del tutorial:

1. ¿Qué es alignItems?

  • Definición: Propiedad que alinea elementos en el eje cruzado del contenedor flex.

  • Relación con flexDirection:

    • Si flexDirection: 'row' → Eje cruzado es vertical → alignItems controla alineación vertical.

    • Si flexDirection: 'column' → Eje cruzado es horizontal → alignItems controla alineación horizontal.

  • Valor por defecto: stretch


2. Configuración inicial del ejemplo

Código base:

jsx

import React from 'react';

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


const App = () => {

  return (

    <View style={styles.container}>

      <View style={styles.boxSize}>

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

      </View>

      <View style={styles.boxSize}>

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

      </View>

      <View style={styles.boxSize}>

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

      </View>

    </View>

  );

};


const styles = StyleSheet.create({

  container: {

    flex: 1,

    flexDirection: 'row', // ← Eje principal: horizontal

    justifyContent: 'space-around',

    alignItems: 'center', // ← Controla alineación VERTICAL (eje cruzado)

  },

  boxSize: {

    width: 100,

    height: 100,

    margin: 5,

    justifyContent: 'center',

    alignItems: 'center',

    backgroundColor: 'gray',

  },

  text: {

    fontSize: 30,

    fontWeight: 'bold',

    color: 'white',

  },

});


export default App;


3. Valores de alignItems con flexDirection: 'row' (eje cruzado: VERTICAL)

1. flex-start

jsx

alignItems: 'flex-start'

  • Comportamiento: Alinea elementos al inicio del eje cruzado (arriba).

  • Visual:

  • text

[1]  [2]  [3]




  • Uso: Para elementos que deben estar pegados arriba.

2. center (el más común)

jsx

alignItems: 'center'

  • Comportamiento: Centra elementos en el eje cruzado.

  • Visual:

  • text

[1]  [2]  [3]


  • Uso: Centrado vertical cuando los elementos tienen altura fija.

3. flex-end

jsx

alignItems: 'flex-end'

  • Comportamiento: Alinea elementos al final del eje cruzado (abajo).

  • Visual:

  • text

  • [1]  [2]  [3]

  • Uso: Para elementos que deben estar abajo.

4. stretch (VALOR POR DEFECTO)

jsx

alignItems: 'stretch'

  • Comportamiento: Estira elementos para llenar el contenedor en el eje cruzado.

  • Condición: Solo funciona si NO hay dimensiones fijas (width/height) en el elemento hijo.

  • Ejemplo práctico:

  • jsx

// En el hijo (boxSize), QUITAMOS la altura:

boxSize: {

  width: 100,

  // height: 100, ← QUITADO para que stretch funcione

  margin: 5,

  backgroundColor: 'gray',

  • }

  • Resultado: Las cajas se estiran verticalmente al 100% del contenedor padre.

5. baseline (menos común)

jsx

alignItems: 'baseline'

  • Comportamiento: Alinea elementos según la línea base del texto.

  • Uso: Para alinear textos de diferentes tamaños.


4. Valores de alignItems con flexDirection: 'column' (eje cruzado: HORIZONTAL)

Cambia el eje cruzado:

jsx

container: {

  flex: 1,

  flexDirection: 'column', // ← Eje principal: vertical

  justifyContent: 'space-around',

  alignItems: 'center', // ← Ahora controla alineación HORIZONTAL

}

  • flex-start → Alinea a la izquierda

  • center → Centra horizontalmente

  • flex-end → Alinea a la derecha

  • stretch → Estira horizontalmente (si no hay width fijo en hijos)


5. Demostración práctica: stretch en acción

Ejemplo 1: stretch con flexDirection: 'row'

jsx

const styles = StyleSheet.create({

  container: {

    flex: 1,

    flexDirection: 'row',

    alignItems: 'stretch', // ← Estirará verticalmente

  },

  boxSize: {

    width: 100, // ← Ancho fijo

    // height: 100, ← SIN altura para que stretch funcione

    margin: 5,

    backgroundColor: 'gray',

  },

});

  • Resultado: Cajas ocuparán todo el alto disponible.

Ejemplo 2: stretch con flexDirection: 'column'

jsx

const styles = StyleSheet.create({

  container: {

    flex: 1,

    flexDirection: 'column',

    alignItems: 'stretch', // ← Estirará horizontalmente

  },

  boxSize: {

    // width: 100, ← SIN ancho para que stretch funcione

    height: 100, // ← Alto fijo

    margin: 5,

    backgroundColor: 'gray',

  },

});

  • Resultado: Cajas ocuparán todo el ancho disponible.


6. Caso especial: stretch con contenido interno

  • Problema: Si un elemento hijo tiene contenido (como texto), stretch puede comportarse inesperadamente.

  • Solución: El hijo se estirará, pero su contenido puede mantener dimensiones propias.

  • Ejemplo:

  • jsx

<View style={styles.boxSize}>

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

  • </View>

    • La caja se estira, pero el texto mantiene su tamaño.


7. Código interactivo para probar todas las opciones

jsx

import React, { useState } from 'react';

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


const alignItemsOptions = [

  'flex-start',

  'center',

  'flex-end',

  'stretch',

  'baseline',

];


const App = () => {

  const [currentAlign, setCurrentAlign] = useState('center');

  const [direction, setDirection] = useState('row');

  const [hasFixedDimensions, setHasFixedDimensions] = useState(true);


  return (

    <View style={styles.main}>

      {/* Controles */}

      <View style={styles.controls}>

        <Text style={styles.title}>Flex Direction:</Text>

        <View style={styles.directionButtons}>

          {['row', 'column'].map((dir) => (

            <TouchableOpacity

              key={dir}

              style={[styles.controlButton, direction === dir && styles.selectedControl]}

              onPress={() => setDirection(dir)}

            >

              <Text style={styles.controlText}>{dir}</Text>

            </TouchableOpacity>

          ))}

        </View>


        <Text style={styles.title}>alignItems:</Text>

        <ScrollView horizontal style={styles.options}>

          {alignItemsOptions.map((option) => (

            <TouchableOpacity

              key={option}

              style={[

                styles.controlButton,

                currentAlign === option && styles.selectedControl,

              ]}

              onPress={() => setCurrentAlign(option)}

            >

              <Text style={styles.controlText}>{option}</Text>

            </TouchableOpacity>

          ))}

        </ScrollView>


        <Text style={styles.title}>Dimensiones en hijos:</Text>

        <TouchableOpacity

          style={[

            styles.controlButton,

            !hasFixedDimensions && styles.selectedControl,

          ]}

          onPress={() => setHasFixedDimensions(!hasFixedDimensions)}

        >

          <Text style={styles.controlText}>

            {hasFixedDimensions ? 'Con dimensiones fijas' : 'Sin dimensiones fijas (stretch funciona)'}

          </Text>

        </TouchableOpacity>

      </View>


      {/* Información */}

      <Text style={styles.info}>

        {`flexDirection: '${direction}'`} | {`alignItems: '${currentAlign}'`}

        {'\n'}

        Eje cruzado: {direction === 'row' ? 'VERTICAL' : 'HORIZONTAL'}

      </Text>


      {/* Contenedor principal */}

      <View style={[styles.container, { 

        flexDirection: direction,

        alignItems: currentAlign,

      }]}>

        <View style={[

          styles.box, 

          hasFixedDimensions && direction === 'row' && styles.boxFixedHeight,

          hasFixedDimensions && direction === 'column' && styles.boxFixedWidth,

        ]}>

          <Text style={styles.boxText}>1</Text>

        </View>

        <View style={[

          styles.box, 

          hasFixedDimensions && direction === 'row' && styles.boxFixedHeight,

          hasFixedDimensions && direction === 'column' && styles.boxFixedWidth,

        ]}>

          <Text style={[styles.boxText, { fontSize: 20 }]}>Texto más pequeño</Text>

        </View>

        <View style={[

          styles.box, 

          hasFixedDimensions && direction === 'row' && styles.boxFixedHeight,

          hasFixedDimensions && direction === 'column' && styles.boxFixedWidth,

        ]}>

          <Text style={styles.boxText}>3</Text>

        </View>

      </View>


      {/* Leyenda */}

      <View style={styles.legend}>

        <Text style={styles.legendText}>

          💡 <Text style={{ fontWeight: 'bold' }}>Nota:</Text> 

          {'\n'}

          • 'stretch' solo funciona si los hijos NO tienen dimensiones fijas en el eje cruzado.

          {'\n'}

          • Con 'row': quita 'height' para ver stretch vertical.

          {'\n'}

          • Con 'column': quita 'width' para ver stretch horizontal.

        </Text>

      </View>

    </View>

  );

};


const styles = StyleSheet.create({

  main: {

    flex: 1,

    paddingTop: 50,

    backgroundColor: '#fff',

  },

  controls: {

    padding: 15,

    backgroundColor: '#f5f5f5',

    borderBottomWidth: 1,

    borderBottomColor: '#ddd',

  },

  title: {

    fontSize: 14,

    fontWeight: 'bold',

    marginTop: 10,

    marginBottom: 5,

    color: '#333',

  },

  directionButtons: {

    flexDirection: 'row',

    marginBottom: 15,

  },

  options: {

    marginBottom: 15,

  },

  controlButton: {

    padding: 10,

    marginRight: 10,

    backgroundColor: '#e0e0e0',

    borderRadius: 5,

    minWidth: 100,

    alignItems: 'center',

  },

  selectedControl: {

    backgroundColor: '#2196F3',

  },

  controlText: {

    color: '#333',

    fontWeight: 'bold',

    fontSize: 12,

  },

  info: {

    textAlign: 'center',

    fontSize: 14,

    fontWeight: 'bold',

    marginVertical: 15,

    color: '#555',

    backgroundColor: '#f9f9f9',

    padding: 10,

  },

  container: {

    flex: 1,

    backgroundColor: '#f0f0f0',

    marginHorizontal: 20,

    marginBottom: 20,

    padding: 20,

    borderWidth: 2,

    borderColor: '#ccc',

    borderRadius: 10,

  },

  box: {

    margin: 10,

    backgroundColor: '#4CAF50',

    borderRadius: 8,

    justifyContent: 'center',

    alignItems: 'center',

    padding: 10,

  },

  boxFixedHeight: {

    height: 80, // Fijo para row (altura en eje cruzado)

  },

  boxFixedWidth: {

    width: 120, // Fijo para column (ancho en eje cruzado)

  },

  boxText: {

    fontSize: 24,

    fontWeight: 'bold',

    color: 'white',

  },

  legend: {

    backgroundColor: '#FFF3CD',

    marginHorizontal: 20,

    marginBottom: 20,

    padding: 15,

    borderRadius: 8,

    borderWidth: 1,

    borderColor: '#FFEAA7',

  },

  legendText: {

    color: '#856404',

    fontSize: 12,

  },

});


export default App;


8. Combinaciones útiles en la práctica

Formulario centrado:

jsx

container: {

  flex: 1,

  flexDirection: 'column',

  justifyContent: 'center',

  alignItems: 'center', // ← Centra horizontalmente

}

Barra de navegación:

jsx

container: {

  flexDirection: 'row',

  alignItems: 'center', // ← Centra verticalmente los íconos/texto

  height: 60,

  backgroundColor: '#fff',

}

Tarjetas de ancho completo:

jsx

container: {

  flexDirection: 'column',

  alignItems: 'stretch', // ← Las tarjetas ocupan todo el ancho

},

card: {

  // Sin width definido para que stretch funcione

  height: 100,

  marginVertical: 5,

}


9. Errores comunes y soluciones

Problema

Solución

stretch no funciona

Quita width (para column) o height (para row) del hijo

Elementos no se alinean

Verifica que flexDirection esté correcto

baseline no hace diferencia

Usa textos de diferentes tamaños

Alineación incorrecta

Recuerda que alignItems trabaja en el eje cruzado


Conclusión:

alignItems es esencial para controlar la alineación perpendicular al flujo principal de elementos. Recuerda:

✅ Eje cruzado depende de flexDirection
stretch es el valor por defecto
stretch requiere hijos sin dimensiones fijas en ese eje
center es el más común para centrar
✅ Combinado con justifyContent controlas ambos ejes

Próximo paso: Aprenderemos sobre alignSelf para alinear elementos individualmente dentro de un contenedor flex.


💡 Tip para depuración: Coloca bordes de colores en tus contenedores para visualizar claramente cómo alignItems afecta la disposición de los elementos


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