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
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 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.
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%.
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).
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.
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.
<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.
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).
<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.
FrameLayout como contenedor estándar para FragmentTransaction. La actividad reemplaza fragmentos dentro de este contenedor según la navegación.
<FrameLayout
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
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.
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
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.
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.
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.
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
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.
Lea también