FrameLayout: concepte cheie, poziționare simplă în Android

Autor: IT Sectr Publicat: 2026-02-24 Timp de citire: 8 min

Învață conceptele cheie ale FrameLayout — cea mai simplă ViewGroup din Android SDK, concepută pentru amplasarea unui element copil (de obicei) sau suprapunerea mai multor elemente. FrameLayout este convenabil pentru containere placeholder, fragmente, indicatoare de încărcare și elemente de prim-plan. Nu gestionează poziționarea copiilor — fiecare element următor este desenat peste precedentul, iar poziția lor este determinată de layout_gravity (left, top, right, bottom, center). Scenariile de bază sunt descrise în FrameLayout API Reference.

Principalele puncte

  • Suprapunerea straturilor — FrameLayout plasează elementele succesiv unul peste altul; ultimul declarat în XML este desenat deasupra tuturor.
  • Foreground — atributul android:foreground permite suprapunerea unui drawable peste toate elementele copil, util pentru efecte și mascare.
  • measureAllChildren — în mod implicit, FrameLayout măsoară toți copiii, chiar și invizibili (GONE). Dezactivarea accelerează randarea cu 20–60%.
  • layout_gravity — singurul mod de poziționare a elementului copil în interiorul FrameLayout: top, bottom, left, right, center.
  • Utilizarea cu Fragment — FrameLayout este containerul standard pentru FragmentTransaction.replace(), înlocuind conținutul fără a recrea activitatea.

Ce este FrameLayout?

FrameLayout este cea mai simplă ViewGroup din Android SDK, proiectată pentru a bloca o zonă a ecranului și a afișa o singură vedere copil (sau a suprapune mai multe). Spre deosebire de LinearLayout (amplasare secvențială) și RelativeLayout (poziționare relativă), FrameLayout nu modifică poziția copiilor — fiecare nou child este plasat implicit în colțul din stânga sus (0,0) și desenat peste precedentul.

FrameLayout a apărut în API Level 1 și rămâne cel mai ușor container Android: nu suprascrie onMeasure cu logică complexă și execută un număr minim de operații de layout. Conform Android Performance Blog, FrameLayout execută onLayout într-o singură trecere și practic nu adaugă overhead comparativ cu amplasarea directă a View. Acest lucru îl face ideal pentru containere unde viteza contează: layout-uri de item-uri RecyclerView (împreună cu ConstraintLayout pentru poziționare), containere de fragmente, straturi de suprapunere.

Dimensiunea implicită a FrameLayout este determinată de cel mai mare element copil (dacă nu este setat match_parent). Dacă niciun child nu este specificat, FrameLayout se reduce la (0,0). Atributul android:measureAllChildren (secțiunea de mai jos) modifică acest comportament.

FrameLayout în ierarhia ViewGroup Android

FrameLayout moștenește ViewGroup și este părintele direct al multor containere specializate: FragmentContainerView (fragmente), CardView (carduri cu umbră), ScrollView (cu un singur child), NestedScrollView. La crearea unei Activity cu navigare prin fragmente, șablonul standard Android Studio utilizează FrameLayout (sau FragmentContainerView) ca container principal pentru fragmente.

Foreground și measureAllChildren

android:foreground — atribut FrameLayout care specifică un drawable desenat peste toate elementele copil. Spre deosebire de background (sub copii), foreground este afișat deasupra conținutului și poate fi transparent. Este utilizat pentru: efecte de suprapunere la apăsare (ripple prin ?attr/selectableItemBackground), mascarea imaginilor, afișarea indicatorilor de stare (bifa de selecție deasupra imaginii).

Foreground suportă resursele standard drawable: ColorDrawable, ShapeDrawable, RippleDrawable, LayerDrawable. Din API 23+ este disponibil android:foregroundGravity pentru poziționarea foreground (fill, center, top, bottom). În modul "umplere" (fill), foreground se întinde pe întreg FrameLayout; în modul center — este desenat în centru.

android:measureAllChildren — atribut boolean (implicit true) care determină dacă toate elementele copil trebuie măsurate la calcularea dimensiunii FrameLayout. Dacă este true (implicit), FrameLayout ia în considerare dimensiunile tuturor copiilor, inclusiv GONE (cu dimensiunea 0). Dacă este false, FrameLayout măsoară doar copiii VISIBLE și INVISIBLE — elementele GONE sunt excluse din calcul. Conform Google I/O 2019, dezactivarea measureAllChildren pentru containerele cu multe elemente GONE (de exemplu, liste cu comutarea vizibilității) accelerează randarea inițială cu 20–60%.

layout_gravity: poziționarea în interiorul FrameLayout

android:layout_gravity — atributul elementului copil al FrameLayout (și al altor ViewGroup) care determină poziția acestuia în interiorul containerului. În FrameLayout, layout_gravity este singurul mod de a controla poziția elementului copil, deoarece FrameLayout nu oferă propriile reguli de poziționare (ca RelativeLayout) sau direcție (ca LinearLayout).

Valori posibile: top, bottom, left, right, center, center_horizontal, center_vertical, fill, fill_horizontal, fill_vertical, clip_horizontal, clip_vertical. Se combină prin |: android:layout_gravity="bottom|center_horizontal" — elementul este lipit de marginea de jos și centrat orizontal. Pentru elementele a căror dimensiune este mai mică decât FrameLayout, layout_gravity determină poziția lor în spațiul liber.

Dacă layout_gravity nu este setat, implicit elementul este plasat în colțul din stânga sus (top|left). Pentru FrameLayout care conține mai mulți copii, fiecare poate avea propriul layout_gravity — un element poate fi în colțul din stânga sus, altul în colțul din dreapta jos, al treilea în centru. Acest lucru permite crearea de suprapuneri simple (de exemplu, un X de închidere peste imagine).

Diferența dintre gravity și layout_gravity

android:gravity (atribut părinte) aliniază conținutul din interiorul FrameLayout — de exemplu, textul din interiorul TextView. android:layout_gravity (atribut copil) aliniază elementul însuși în interiorul FrameLayout. În contextul FrameLayout, gravity determină modul în care copiii sunt aranjați implicit (analog layout_gravity pentru toți copiii deodată), dar layout_gravity al fiecărui element specific suprascrie valoarea părintelui.

Exemple: XML și cazuri de utilizare

Exemplul 1: Suprapunere de bază — etichetă pe imagine

Imagine și etichetă text în colțul din dreapta jos. FrameLayout conține ImageView pe tot ecranul și TextView cu layout_gravity="bottom|end" pentru poziționare deasupra.

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 ocupă întreg FrameLayout (200dp înălțime). TextView cu layout_gravity="bottom|end" este plasat în colțul din dreapta jos deasupra imaginii. elevation=2dp adaugă umbră sub etichetă, separând-o vizual de imagine. Acesta este un exemplu minimal care în LinearLayout ar necesita un container imbricat sau cod personalizat.

Exemplul 2: Indicator de încărcare (bară de progres peste conținut)

Ecran cu conținut și o bară de progres în centru care apare la încărcare. FrameLayout conține două elemente: conținutul și ProgressBar cu visibility="gone" (comutat în cod).

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="Conținut încărcat"
        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>

ProgressBar este ascuns implicit (gone). La începerea încărcării, în cod se apelează findViewById(R.id.loading_spinner).visibility = View.VISIBLE — spinnerul apare în centru deasupra conținutului. După încărcare — .visibility = View.GONE. FrameLayout asigură suprapunerea fără a modifica poziția conținutului — textul nu se deplasează la apariția spinnerului, deoarece ProgressBar este desenat deasupra.

Exemplul 3: Container de fragmente

FrameLayout ca container standard pentru FragmentTransaction. Activitatea înlocuiește fragmentele în interiorul acestui container în funcție de navigare.

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 ca container de fragmente — cel mai ușor mod de a suporta Fragment Navigation. FragmentContainerView (moștenitor al FrameLayout) este recomandat cu Navigation Component 2.4+, dar FrameLayout simplu rămâne valid pentru FragmentTransaction manuale. Avantajul cheie — FragmentTransaction.replace() înlocuiește complet conținutul fără a afecta Activity.

Când să utilizați FrameLayout

FrameLayout este optim pentru patru scenarii: container de fragmente (FragmentContainerView sau FrameLayout), suprapunere de încărcare (ProgressBar peste conținut), etichete pe carduri (semn pe imagine), container placeholder pentru ViewStub (încărcare leneșă).

Nu este potrivit pentru: poziționarea complexă a mai multor elemente (utilizați ConstraintLayout), liste secvențiale (LinearLayout sau RecyclerView), layout-uri dinamice cu modificarea ordinii elementelor.

FrameLayout ca element rădăcină al ecranului — o practică proastă dacă ecranul conține mai mult de 2–3 elemente. Pentru containerul rădăcină utilizați ConstraintLayout — oferă mai mult control asupra poziționării fără pierderi de performanță. FrameLayout utilizați doar pentru blocuri copil unde este necesară suprapunerea sau un placeholder.

Întrebări frecvente

Care este diferența dintre FrameLayout și ConstraintLayout?

FrameLayout — un container minimalist fără sistem de poziționare (doar layout_gravity), destinat suprapunerii elementelor. ConstraintLayout — un sistem de layout complet cu constrângeri, lanțuri, bariere, dimensiuni procentuale și suport MotionLayout. FrameLayout este mai rapid pentru cazuri simple (1 child sau overlay); ConstraintLayout este obligatoriu pentru layout-uri complexe. Alegere: FrameLayout pentru suprapunerea de încărcare și container de fragmente; ConstraintLayout pentru orice altceva.

Cum fac ca FrameLayout să ocupe doar locul celui mai mare child?

Setați dimensiunea FrameLayout la wrap_content pe axa dorită (android:layout_width="wrap_content" și/sau android:layout_height="wrap_content"). În acest caz, FrameLayout se va adapta la dimensiunea celui mai mare element copil. Dacă toți copiii sunt mai mici decât FrameLayout, spațiul suplimentar va rămâne gol. Pentru control precis, utilizați match_parent cu padding fix.

De ce elementele din FrameLayout se suprapun unele peste altele?

Acesta este comportamentul normal al FrameLayout — nu distribuie copiii în spațiu, ci îi desenează succesiv unul peste altul. Dacă doriți ca elementele să nu se suprapună, utilizați un alt container (LinearLayout, ConstraintLayout). Pentru suprapunere parțială cu controlul ordinii de desenare, utilizați layout_gravity pentru deplasare și elevation pentru Z-order.

Ce este mai rapid: FrameLayout sau ConstraintLayout?

FrameLayout este mai rapid pentru cazuri extrem de simple — un singur element copil, fără poziționare complexă. FrameLayout execută onMeasure în timp minim, fără a calcula constrângeri. Cu toate acestea, diferența este vizibilă doar la sute de repetări (RecyclerView cu zeci de mii de elemente). Pentru un ecran obișnuit (1–3 FrameLayout), diferența este de microsecunde și nu afectează UX. ConstraintLayout este alegerea universală pentru 95% din sarcini.

Rezumat

  • FrameLayout — cea mai simplă ViewGroup Android pentru suprapunerea elementelor și containere placeholder cu overhead minim.
  • Suprapunerea straturilor — fiecare nou child este desenat peste precedentul; ultimul declarat în XML este deasupra.
  • Foreground — drawable deasupra tuturor copiilor pentru efecte de suprapunere, mascare și animație ripple.
  • measureAllChildren — dezactivarea (false) exclude elementele GONE din calculul dimensiunii, accelerând randarea cu 20–60%.
  • layout_gravity — singurul mecanism de poziționare: top, bottom, left, right, center și combinațiile lor.
  • Container de fragmente — cel mai frecvent caz de utilizare: FrameLayout (sau FragmentContainerView) pentru FragmentTransaction.replace().
  • Performanță — cel mai rapid container pentru 1 child; pentru layout-uri complexe, este inferior ConstraintLayout.

Vom dezvolta o aplicație mobilă la cheie

IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.

Discutați proiectul

Citiți și