Découvrez les concepts clés de FrameLayout — la ViewGroup la plus simple du SDK Android, conçue pour héberger un seul élément enfant (généralement) ou superposer plusieurs éléments les uns sur les autres. FrameLayout est pratique pour les conteneurs placeholder, les fragments, les indicateurs de chargement et les éléments de premier plan. Il ne gère pas le positionnement des enfants — chaque élément suivant est dessiné par-dessus le précédent, et leur position est déterminée par layout_gravity (left, top, right, bottom, center). Les scénarios de base sont décrits dans la Référence API FrameLayout.
Points clés
FrameLayout est la ViewGroup la plus simple du SDK Android, conçue pour bloquer une zone de l'écran et afficher une seule vue enfant (ou en superposer plusieurs). Contrairement à LinearLayout (disposition séquentielle) et RelativeLayout (positionnement relatif), FrameLayout ne modifie pas les positions des enfants — chaque nouvel enfant est placé dans le coin supérieur gauche (0,0) par défaut et dessiné par-dessus le précédent.
FrameLayout a été introduit dans l'API Level 1 et reste le conteneur Android le plus léger : il ne remplace pas onMeasure par une logique complexe et effectue un nombre minimal d'opérations de layout. Selon Android Performance Blog, FrameLayout exécute onLayout en un seul passage et n'ajoute pratiquement aucun surcoût par rapport au placement direct d'une View. Cela en fait un choix idéal pour les conteneurs où la vitesse compte : layouts d'éléments RecyclerView (associés à ConstraintLayout pour le positionnement), conteneurs de fragments, couches de superposition.
La taille de FrameLayout est déterminée par défaut par le plus grand élément enfant (si match_parent n'est pas défini). Si aucun enfant n'est spécifié, FrameLayout se réduit à (0,0). L'attribut android:measureAllChildren (section ci-dessous) modifie ce comportement.
FrameLayout hérite de ViewGroup et est le parent direct de nombreux conteneurs spécialisés : FragmentContainerView (fragments), CardView (cartes avec ombre), ScrollView (enfant unique), NestedScrollView. Lors de la création d'une Activity avec navigation par fragments, le modèle standard d'Android Studio utilise FrameLayout (ou FragmentContainerView) comme conteneur racine pour les fragments.
android:foreground — un attribut FrameLayout qui spécifie un drawable dessiné par-dessus tous les éléments enfants. Contrairement à background (sous les enfants), foreground s'affiche au-dessus du contenu et peut être transparent. Il est utilisé pour : les effets de superposition au toucher (ripple via ?attr/selectableItemBackground), le masquage d'images, l'affichage d'indicateurs d'état (coche de sélection sur une image).
Foreground prend en charge les ressources drawable standard : ColorDrawable, ShapeDrawable, RippleDrawable, LayerDrawable. Depuis l'API 23+, android:foregroundGravity est disponible pour le positionnement du premier plan (fill, center, top, bottom). En mode remplissage (fill), le foreground s'étend sur tout le FrameLayout ; en mode centre, il se dessine au centre.
android:measureAllChildren — un attribut booléen (true par défaut) qui détermine si tous les éléments enfants doivent être mesurés lors du calcul de la taille de FrameLayout. Si true (par défaut), FrameLayout prend en compte les tailles de tous les enfants, y compris GONE (avec une taille de 0). Si false, FrameLayout mesure uniquement les enfants VISIBLE et INVISIBLE — les éléments GONE sont exclus du calcul. Selon Google I/O 2019, désactiver measureAllChildren pour les conteneurs avec de nombreux éléments GONE (par exemple, les listes à visibilité alternée) accélère le dessin initial de 20 à 60 %.
android:layout_gravity — un attribut d'un élément enfant de FrameLayout (et d'autres ViewGroups) qui définit sa position à l'intérieur du conteneur. Dans FrameLayout, layout_gravity est le seul moyen de contrôler la position d'un élément enfant, car FrameLayout ne fournit pas ses propres règles de positionnement (comme RelativeLayout) ni de direction (comme LinearLayout).
Valeurs possibles : top, bottom, left, right, center, center_horizontal, center_vertical, fill, fill_horizontal, fill_vertical, clip_horizontal, clip_vertical. Combinées via | : android:layout_gravity="bottom|center_horizontal" — l'élément est fixé au bord inférieur et centré horizontalement. Pour les éléments plus petits que FrameLayout, layout_gravity détermine leur position dans l'espace libre.
Si layout_gravity n'est pas défini, l'élément est placé dans le coin supérieur gauche (top|left) par défaut. Pour un FrameLayout contenant plusieurs enfants, chacun peut avoir son propre layout_gravity — un élément peut être dans le coin supérieur gauche, un autre dans le coin inférieur droit, un troisième centré. Cela permet de créer des superpositions simples (par exemple, une icône de fermeture sur une image).
android:gravity (attribut parent) aligne le contenu à l'intérieur de FrameLayout — par exemple, le texte dans un TextView. android:layout_gravity (attribut enfant) aligne l'élément lui-même à l'intérieur de FrameLayout. Dans le contexte de FrameLayout, gravity définit comment les enfants sont positionnés par défaut (similaire à layout_gravity pour tous les enfants à la fois), mais le layout_gravity de chaque élément spécifique remplace la valeur parente.
Une image avec une étiquette de texte dans le coin inférieur droit. FrameLayout contient un ImageView remplissant l'écran et un TextView avec layout_gravity="bottom|end" pour le positionnement sur l'image.
<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 remplit tout le FrameLayout (hauteur 200dp). Le TextView avec layout_gravity="bottom|end" est placé dans le coin inférieur droit sur l'image. elevation=2dp ajoute une ombre sous l'étiquette, la séparant visuellement de l'image. Cet exemple minimal aurait nécessité un conteneur imbriqué ou du code personnalisé dans LinearLayout.
Un écran avec du contenu et une barre de progression centrée qui apparaît pendant le chargement. FrameLayout contient deux éléments : le contenu et un ProgressBar avec visibility="gone" (basculé dans le code).
<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="Contenu chargé"
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>
La ProgressBar est masquée par défaut (gone). Au début du chargement, findViewById(R.id.loading_spinner).visibility = View.VISIBLE est appelé — le spinner apparaît centré sur le contenu. Après le chargement — .visibility = View.GONE. FrameLayout assure la superposition sans déplacer la position du contenu — le texte ne bouge pas lorsque le spinner apparaît, car la ProgressBar se dessine par-dessus.
FrameLayout comme conteneur standard pour FragmentTransaction. L'activité remplace les fragments à l'intérieur de ce conteneur selon la navigation.
<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 comme conteneur de fragments est le moyen le plus léger de prendre en charge la navigation par fragments. FragmentContainerView (une sous-classe de FrameLayout) est recommandé avec Navigation Component 2.4+, mais un simple FrameLayout reste valide pour les FragmentTransactions manuelles. L'avantage clé est que FragmentTransaction.replace() remplace complètement le contenu sans affecter l'Activity.
FrameLayout est optimal pour quatre scénarios : conteneur de fragments (FragmentContainerView ou FrameLayout), superposition de chargement (ProgressBar sur le contenu), étiquettes de cartes (étiquette sur image), conteneur placeholder pour ViewStub (chargement différé).
Ne convient pas pour : le positionnement complexe de plusieurs éléments (utilisez ConstraintLayout), les listes séquentielles (LinearLayout ou RecyclerView), les layouts dynamiques avec changement d'ordre des éléments.
FrameLayout comme élément racine de l'écran — mauvaise pratique si l'écran contient plus de 2 à 3 éléments. Pour un conteneur racine, utilisez ConstraintLayout — il offre plus de contrôle sur le positionnement sans perte de performances. Utilisez FrameLayout uniquement pour les blocs enfants où une superposition ou un placeholder est nécessaire.
Foire aux questions
FrameLayout — un conteneur minimaliste sans système de positionnement (uniquement layout_gravity), conçu pour la superposition d'éléments. ConstraintLayout — un système de layout complet avec contraintes, chaînes, barrières, dimensions en pourcentage et support de MotionLayout. FrameLayout est plus rapide pour les cas simples (1 enfant ou superposition) ; ConstraintLayout est nécessaire pour les layouts complexes. Choix : FrameLayout pour la superposition de chargement et le conteneur de fragments ; ConstraintLayout pour tout le reste.
Définissez la taille de FrameLayout sur wrap_content sur l'axe souhaité (android:layout_width="wrap_content" et/ou android:layout_height="wrap_content"). FrameLayout s'ajustera alors à la taille du plus grand élément enfant. Si tous les enfants sont plus petits que FrameLayout, l'espace excédentaire reste vide. Pour un contrôle précis, utilisez match_parent avec un padding fixe.
C'est le comportement prévu de FrameLayout — il ne distribue pas les enfants dans l'espace mais les dessine séquentiellement les uns sur les autres. Si vous ne voulez pas que les éléments se chevauchent, utilisez un autre conteneur (LinearLayout, ConstraintLayout). Pour un chevauchement partiel avec contrôle de l'ordre de dessin, utilisez layout_gravity pour le décalage et elevation pour l'ordre Z.
FrameLayout est plus rapide pour les cas les plus simples — un élément enfant, sans positionnement complexe. FrameLayout exécute onMeasure en un temps minimal sans calculer de contraintes. Cependant, la différence n'est perceptible qu'à des centaines de répétitions (RecyclerView avec des dizaines de milliers d'éléments). Pour un écran typique (1 à 3 FrameLayouts), la différence est de l'ordre de la microseconde et n'affecte pas l'UX. ConstraintLayout est le choix universel pour 95 % des tâches.
Résumé
Nous développerons une application mobile clé en main
IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.
Lisez aussi