FrameLayout: Conceptos clave, posicionamiento simple en Android

Autor: IT Sectr Publicado: 2026-02-24 Tiempo de lectura: 8 min

Conozca los conceptos clave de FrameLayout — la ViewGroup más simple en Android SDK, diseñada para alojar un único elemento hijo (normalmente) o superponer varios elementos uno sobre otro. FrameLayout es útil para contenedores placeholder, fragmentos, indicadores de carga y elementos de primer plano. No gestiona la posición de los hijos — cada elemento subsiguiente se dibuja sobre el anterior, y su posición se determina mediante layout_gravity (left, top, right, bottom, center). Los escenarios básicos se describen en la Referencia de la API de FrameLayout.

Puntos clave

  • Superposición de capas — FrameLayout coloca los elementos secuencialmente uno sobre otro; el último declarado en XML se dibuja en la posición más alta.
  • Foreground — el atributo android:foreground permite superponer un drawable sobre todos los elementos hijos, útil para efectos y enmascaramiento.
  • measureAllChildren — por defecto, FrameLayout mide todos los hijos, incluso los invisibles (GONE). Desactivarlo acelera el dibujo entre un 20 y un 60%.
  • layout_gravity — la única forma de posicionar un elemento hijo dentro de FrameLayout: top, bottom, left, right, center.
  • Uso con Fragment — FrameLayout es el contenedor estándar para FragmentTransaction.replace(), que reemplaza el contenido sin recrear la actividad.

¿Qué es FrameLayout?

FrameLayout es la ViewGroup más simple en Android SDK, diseñada para bloquear un área de la pantalla y mostrar una única vista hija (o superponer varias). A diferencia de LinearLayout (colocación secuencial) y RelativeLayout (posicionamiento relativo), FrameLayout no altera las posiciones de los hijos — cada nuevo hijo se coloca en la esquina superior izquierda (0,0) por defecto y se dibuja sobre el anterior.

FrameLayout se introdujo en API Level 1 y sigue siendo el contenedor Android más ligero: no sobrescribe onMeasure con lógica compleja y realiza un número mínimo de operaciones de layout. Según Android Performance Blog, FrameLayout ejecuta onLayout en un solo paso y prácticamente no añade sobrecarga en comparación con colocar una View directamente. Esto lo convierte en una opción ideal para contenedores donde la velocidad importa: layouts de elementos de RecyclerView (combinados con ConstraintLayout para el posicionamiento), contenedores de Fragment, capas superpuestas.

El tamaño de FrameLayout por defecto se determina por el elemento hijo más grande (si no se establece match_parent). Si no se especifica ningún hijo, FrameLayout se colapsa a (0,0). El atributo android:measureAllChildren (sección siguiente) modifica este comportamiento.

FrameLayout en la jerarquía de ViewGroup de Android

FrameLayout hereda de ViewGroup y es el padre directo de muchos contenedores especializados: FragmentContainerView (fragmentos), CardView (tarjetas con sombra), ScrollView (un único hijo), NestedScrollView. Al crear una Activity con navegación por Fragmentos, la plantilla estándar de Android Studio utiliza FrameLayout (o FragmentContainerView) como contenedor raíz para los fragmentos.

Foreground y measureAllChildren

android:foreground — un atributo de FrameLayout que especifica un drawable que se dibuja sobre todos los elementos hijos. A diferencia de background (debajo de los hijos), foreground se muestra sobre el contenido y puede ser transparente. Se utiliza para: efectos de superposición al pulsar (ripple mediante ?attr/selectableItemBackground), enmascaramiento de imágenes, visualización de indicadores de estado (marca de verificación sobre una imagen).

Foreground admite recursos drawable estándar: ColorDrawable, ShapeDrawable, RippleDrawable, LayerDrawable. Desde API 23+, está disponible android:foregroundGravity para posicionar el foreground (fill, center, top, bottom). En modo relleno (fill), foreground se estira por todo FrameLayout; en modo center, se dibuja en el centro.

android:measureAllChildren — un atributo booleano (true por defecto) que determina si se deben medir todos los elementos hijos al calcular el tamaño de FrameLayout. Si es true (por defecto), FrameLayout tiene en cuenta los tamaños de todos los hijos, incluidos los GONE (con tamaño 0). Si es false, FrameLayout mide solo los hijos VISIBLE e INVISIBLE — los elementos GONE se excluyen del cálculo. Según Google I/O 2019, desactivar measureAllChildren en contenedores con muchos elementos GONE (por ejemplo, listas con visibilidad alternante) acelera el dibujo inicial entre un 20 y un 60%.

layout_gravity: Posicionamiento dentro de FrameLayout

android:layout_gravity — un atributo del elemento hijo de FrameLayout (y otras ViewGroups) que define su posición dentro del contenedor. En FrameLayout, layout_gravity es la única forma de controlar la posición de un elemento hijo, ya que FrameLayout no proporciona sus propias reglas de posicionamiento (como RelativeLayout) ni dirección (como LinearLayout).

Valores posibles: top, bottom, left, right, center, center_horizontal, center_vertical, fill, fill_horizontal, fill_vertical, clip_horizontal, clip_vertical. Se combinan mediante |: android:layout_gravity="bottom|center_horizontal" — el elemento se adhiere al borde inferior y se centra horizontalmente. Para elementos más pequeños que FrameLayout, layout_gravity determina su posición en el espacio libre.

Si no se establece layout_gravity, el elemento se coloca en la esquina superior izquierda (top|left) por defecto. Para un FrameLayout que contiene varios hijos, cada uno puede tener su propio layout_gravity — un elemento puede estar en la esquina superior izquierda, otro en la esquina inferior derecha, un tercero centrado. Esto permite crear superposiciones simples (por ejemplo, un icono de cierre sobre una imagen).

Diferencia: gravity vs layout_gravity

android:gravity (atributo padre) alinea el contenido dentro de FrameLayout — por ejemplo, el texto dentro de un TextView. android:layout_gravity (atributo hijo) alinea el elemento mismo dentro de FrameLayout. En el contexto de FrameLayout, gravity define cómo se posicionan los hijos por defecto (similar a layout_gravity para todos los hijos a la vez), pero el layout_gravity de cada elemento concreto anula el valor del padre.

Ejemplos: XML y casos de uso

Ejemplo 1: Superposición básica — Etiqueta sobre imagen

Una imagen con una etiqueta de texto en la esquina inferior derecha. FrameLayout contiene un ImageView que ocupa toda la pantalla y un TextView con layout_gravity="bottom|end" para posicionarse sobre la imagen.

xml
<FrameLayout
    android:layout_width="match_parent"
    android:layout_height="200dp">

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:src="@drawable/product_photo"
        android:scaleType="centerCrop" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:layout_margin="8dp"
        android:background="@drawable/badge_background"
        android:elevation="2dp"
        android:paddingHorizontal="8dp"
        android:paddingVertical="4dp"
        android:text="-30%"
        android:textColor="@android:color/white"
        android:textSize="14sp"
        android:textStyle="bold" />

</FrameLayout>

ImageView ocupa todo el FrameLayout (200dp de altura). El TextView con layout_gravity="bottom|end" se coloca en la esquina inferior derecha sobre la imagen. elevation=2dp añade una sombra bajo la etiqueta, separándola visualmente de la imagen. Este ejemplo mínimo requeriría un contenedor anidado o código personalizado en LinearLayout.

Ejemplo 2: Indicador de carga (barra de progreso sobre el contenido)

Una pantalla con contenido y una barra de progreso centrada que aparece durante la carga. FrameLayout contiene dos elementos: contenido y un ProgressBar con visibility="gone" (alternado en código).

xml
<FrameLayout
    android:id="@+id/content_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/content_text"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:text="Contenido cargado"
        android:textSize="18sp" />

    <ProgressBar
        android:id="@+id/loading_spinner"
        android:layout_width="48dp"
        android:layout_height="48dp"
        android:layout_gravity="center"
        android:visibility="gone" />

</FrameLayout>

El ProgressBar está oculto por defecto (gone). Al iniciar la carga, se llama a findViewById(R.id.loading_spinner).visibility = View.VISIBLE — el spinner aparece centrado sobre el contenido. Después de la carga — .visibility = View.GONE. FrameLayout proporciona superposición sin desplazar la posición del contenido — el texto no se mueve cuando aparece el spinner, ya que el ProgressBar se dibuja encima.

Ejemplo 3: Contenedor de Fragment

FrameLayout como contenedor estándar para FragmentTransaction. La actividad reemplaza fragmentos dentro de este contenedor según la navegación.

xml
<FrameLayout
    android:id="@+id/fragment_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
kotlin
import androidx.fragment.app.FragmentTransaction

val fragmentContainer = R.id.fragment_container

fun navigateTo(fragment: Fragment) {
    supportFragmentManager
        .beginTransaction()
        .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
        .replace(fragmentContainer, fragment)
        .addToBackStack(null)
        .commit()
}

FrameLayout como contenedor de fragmentos es la forma más ligera de admitir la navegación por Fragmentos. Se recomienda FragmentContainerView (subclase de FrameLayout) con Navigation Component 2.4+, pero un FrameLayout simple sigue siendo válido para FragmentTransaction manuales. La ventaja clave es que FragmentTransaction.replace() reemplaza completamente el contenido sin afectar a la Activity.

Cuándo usar FrameLayout

FrameLayout es óptimo para cuatro escenarios: contenedor de fragmentos (FragmentContainerView o FrameLayout), superposición de carga (ProgressBar sobre contenido), etiquetas en tarjetas (etiqueta sobre imagen), contenedor placeholder para ViewStub (carga diferida).

No es adecuado para: posicionamiento complejo de varios elementos (use ConstraintLayout), listas secuenciales (LinearLayout o RecyclerView), layouts dinámicos con cambio de orden de elementos.

FrameLayout como elemento raíz de la pantalla — mala práctica si la pantalla contiene más de 2–3 elementos. Para un contenedor raíz, use ConstraintLayout — proporciona más control sobre el posicionamiento sin pérdida de rendimiento. Use FrameLayout solo para bloques hijos donde se necesite superposición o placeholder.

Preguntas frecuentes

¿Cuál es la diferencia entre FrameLayout y ConstraintLayout?

FrameLayout — un contenedor minimalista sin sistema de posicionamiento (solo layout_gravity), diseñado para la superposición de elementos. ConstraintLayout — un sistema de layout completo con constraints, cadenas, barreras, dimensiones porcentuales y soporte de MotionLayout. FrameLayout es más rápido para casos simples (1 hijo o superposición); ConstraintLayout es necesario para layouts complejos. Elección: FrameLayout para superposición de carga y contenedor de fragmentos; ConstraintLayout para todo lo demás.

¿Cómo hacer que FrameLayout ocupe solo el espacio del hijo más grande?

Establezca el tamaño de FrameLayout en wrap_content en el eje deseado (android:layout_width="wrap_content" y/o android:layout_height="wrap_content"). FrameLayout se ajustará entonces al tamaño del elemento hijo más grande. Si todos los hijos son más pequeños que FrameLayout, el espacio sobrante permanece vacío. Para un control preciso, use match_parent con padding fijo.

¿Por qué los elementos en FrameLayout se superponen entre sí?

Este es el comportamiento previsto de FrameLayout — no distribuye los hijos en el espacio sino que los dibuja secuencialmente uno sobre otro. Si desea que los elementos no se superpongan, use otro contenedor (LinearLayout, ConstraintLayout). Para superposición parcial con control del orden de dibujo, use layout_gravity para el desplazamiento y elevation para el orden Z.

¿Qué es más rápido: FrameLayout o ConstraintLayout?

FrameLayout es más rápido para los casos más simples — un elemento hijo, sin posicionamiento complejo. FrameLayout ejecuta onMeasure en un tiempo mínimo sin calcular constraints. Sin embargo, la diferencia es notable solo en cientos de repeticiones (RecyclerView con decenas de miles de elementos). Para una pantalla típica (1–3 FrameLayouts), la diferencia es de microsegundos y no afecta a la experiencia de usuario. ConstraintLayout es la opción universal para el 95% de las tareas.

Resumen

  • FrameLayout — la ViewGroup Android más simple para superposición de elementos y contenedores placeholder con mínima sobrecarga.
  • Superposición de capas — cada nuevo hijo se dibuja sobre el anterior; el último declarado en XML es el más superior.
  • Foreground — un drawable sobre todos los hijos para efectos de superposición, enmascaramiento y animaciones ripple.
  • measureAllChildren — desactivarlo (false) excluye los elementos GONE del cálculo de tamaño, acelerando el dibujo entre un 20 y un 60%.
  • layout_gravity — el único mecanismo de posicionamiento: top, bottom, left, right, center y sus combinaciones.
  • Contenedor de Fragment — el caso de uso más común: FrameLayout (o FragmentContainerView) para FragmentTransaction.replace().
  • Rendimiento — el contenedor más rápido para 1 hijo; para layouts complejos, queda detrás de ConstraintLayout.

Desarrollaremos una aplicación móvil llave en mano

IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.

Discutir el proyecto

Lea también