Î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
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 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.
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%.
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).
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.
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.
<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.
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).
<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.
FrameLayout ca container standard pentru FragmentTransaction. Activitatea înlocuiește fragmentele în interiorul acestui container în funcție de navigare.
<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 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.
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
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.
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.
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.
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
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.
Citiți și