FrameLayout: kluczowe pojęcia, proste pozycjonowanie w Androidzie

Autor: IT Sectr Opublikowano: 2026-02-24 Czas czytania: 8 min

Poznaj kluczowe pojęcia FrameLayout — najprostszą ViewGroup w Android SDK, przeznaczoną do umieszczania jednego elementu potomnego (zwykle) lub nakładania kilku elementów na siebie. FrameLayout jest wygodny dla kontenerów zastępczych, fragmentów, wskaźników ładowania i elementów pierwszego planu. Nie zarządza rozmieszczeniem dzieci — każdy kolejny element rysowany jest nad poprzednim, a ich pozycja określana jest przez layout_gravity (left, top, right, bottom, center). Podstawowe scenariusze opisane są w FrameLayout API Reference.

Najważniejsze

  • Nakładanie warstw — FrameLayout umieszcza elementy kolejno jeden na drugim; ostatni zadeklarowany w XML rysowany jest nad wszystkimi.
  • Foreground — atrybut android:foreground pozwala nałożyć drawable na wszystkie elementy potomne, przydatne do efektów i maskowania.
  • measureAllChildren — domyślnie FrameLayout mierzy wszystkie dzieci, nawet niewidoczne (GONE). Wyłączenie przyspiesza renderowanie o 20–60%.
  • layout_gravity — jedyny sposób pozycjonowania elementu potomnego wewnątrz FrameLayout: top, bottom, left, right, center.
  • Użycie z Fragment — FrameLayout to standardowy kontener dla FragmentTransaction.replace(), zastępujący zawartość bez odtwarzania aktywności.

Co to jest FrameLayout?

FrameLayout to najprostsza ViewGroup w Android SDK, zaprojektowana do blokowania obszaru ekranu i wyświetlania jednego widoku potomnego (lub nakładania kilku). W przeciwieństwie do LinearLayout (sekwencyjne rozmieszczanie) i RelativeLayout (względne pozycjonowanie), FrameLayout nie zmienia pozycji dzieci — każdy nowy child umieszczany jest domyślnie w lewym górnym rogu (0,0) i rysowany nad poprzednim.

FrameLayout pojawił się w API Level 1 i pozostaje najlżejszym kontenerem Androida: nie nadpisuje onMeasure złożoną logiką i wykonuje minimalną liczbę operacji layout. Według Android Performance Blog, FrameLayout wykonuje onLayout w jednym przebiegu i praktycznie nie dodaje narzutu w porównaniu z bezpośrednim umieszczeniem View. Czyni to go idealnym wyborem dla kontenerów, gdzie liczy się szybkość: layouty itemów RecyclerView (w parze z ConstraintLayout do pozycjonowania), kontenery fragmentów, warstwy nakładkowe.

Rozmiar FrameLayout domyślnie określany jest przez największy element potomny (jeśli nie ustawiono match_parent). Jeśli nie określono żadnego child, FrameLayout zwija się do (0,0). Atrybut android:measureAllChildren (sekcja poniżej) zmienia to zachowanie.

FrameLayout w hierarchii Android ViewGroup

FrameLayout dziedziczy po ViewGroup i jest bezpośrednim rodzicem wielu wyspecjalizowanych kontenerów: FragmentContainerView (fragmenty), CardView (karty z cieniem), ScrollView (z jednym child), NestedScrollView. Podczas tworzenia Activity z nawigacją Fragment standardowy szablon Android Studio używa FrameLayout (lub FragmentContainerView) jako głównego kontenera dla fragmentów.

Foreground i measureAllChildren

android:foreground — atrybut FrameLayout, określający drawable rysowany nad wszystkimi elementami potomnymi. W przeciwieństwie do background (pod dziećmi), foreground wyświetlany jest nad zawartością i może być przezroczysty. Używany do: efektów nakładkowych przy naciśnięciu (ripple przez ?attr/selectableItemBackground), maskowania obrazów, wyświetlania wskaźników stanu (znacznik wyboru nad obrazkiem).

Foreground obsługuje standardowe zasoby drawable: ColorDrawable, ShapeDrawable, RippleDrawable, LayerDrawable. Od API 23+ dostępny jest android:foregroundGravity do pozycjonowania foreground (fill, center, top, bottom). W trybie „wypełnij" (fill) foreground rozciąga się na cały FrameLayout; w trybie center — rysowany jest na środku.

android:measureAllChildren — atrybut logiczny (true domyślnie), określający czy należy mierzyć wszystkie elementy potomne przy obliczaniu rozmiaru FrameLayout. Jeśli true (domyślnie), FrameLayout uwzględnia rozmiary wszystkich dzieci, włączając GONE (o rozmiarze 0). Jeśli false, FrameLayout mierzy tylko widoczne (VISIBLE) i niewidoczne (INVISIBLE) dzieci — elementy GONE są wykluczane z obliczeń. Według Google I/O 2019, wyłączenie measureAllChildren dla kontenerów z dużą liczbą elementów GONE (np. listy z przełączaniem widoczności) przyspiesza początkowe renderowanie o 20–60%.

layout_gravity: pozycjonowanie wewnątrz FrameLayout

android:layout_gravity — atrybut elementu potomnego FrameLayout (i innych ViewGroup), określający jego pozycję wewnątrz kontenera. W FrameLayout layout_gravity to jedyny sposób zarządzania położeniem elementu potomnego, ponieważ FrameLayout nie udostępnia własnych reguł pozycjonowania (jak RelativeLayout) ani kierunku (jak LinearLayout).

Możliwe wartości: top, bottom, left, right, center, center_horizontal, center_vertical, fill, fill_horizontal, fill_vertical, clip_horizontal, clip_vertical. Łączy się przez |: android:layout_gravity="bottom|center_horizontal" — element jest dociskany do dolnej krawędzi i wyśrodkowany poziomo. Dla elementów, których rozmiar jest mniejszy niż FrameLayout, layout_gravity określa ich pozycję w wolnej przestrzeni.

Jeśli layout_gravity nie jest ustawiony, domyślnie element umieszczany jest w lewym górnym rogu (top|left). Dla FrameLayout zawierającego kilka dzieci, każde może mieć własny layout_gravity — jeden element może być w lewym górnym rogu, drugi w prawym dolnym, trzeci na środku. Pozwala to tworzyć proste nakładania (np. krzyżyk zamykania nad obrazkiem).

Różnica gravity vs layout_gravity

android:gravity (atrybut rodzica) wyrównuje zawartość wewnątrz FrameLayout — na przykład tekst wewnątrz TextView. android:layout_gravity (atrybut dziecka) wyrównuje sam element wewnątrz FrameLayout. W kontekście FrameLayout gravity określa jak dzieci są rozmieszczane domyślnie (odpowiednik layout_gravity dla wszystkich dzieci naraz), ale layout_gravity każdego konkretnego elementu nadpisuje wartość rodzica.

Przykłady: XML i przypadki użycia

Przykład 1: Podstawowe nakładanie — etykieta na obrazie

Obraz i etykieta tekstowa w prawym dolnym rogu. FrameLayout zawiera ImageView na cały ekran i TextView z layout_gravity="bottom|end" do pozycjonowania na wierzchu.

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 zajmuje cały FrameLayout (200dp wysokości). TextView z layout_gravity="bottom|end" umieszczany jest w prawym dolnym rogu nad obrazem. elevation=2dp dodaje cień pod etykietą, oddzielając ją wizualnie od obrazu. To minimalny przykład, który w LinearLayout wymagałby zagnieżdżonego kontenera lub kodu niestandardowego.

Przykład 2: Wskaźnik ładowania (pasek postępu nad treścią)

Ekran z treścią i paskiem postępu na środku, który pojawia się podczas ładowania. FrameLayout zawiera dwa elementy: treść i ProgressBar z visibility="gone" (przełączany w kodzie).

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="Załadowana treść"
        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 domyślnie ukryty (gone). Po rozpoczęciu ładowania w kodzie wywoływane jest findViewById(R.id.loading_spinner).visibility = View.VISIBLE — spinner pojawia się na środku nad treścią. Po zakończeniu ładowania — .visibility = View.GONE. FrameLayout zapewnia nakładanie bez zmiany pozycji treści — tekst nie przesuwa się przy pojawieniu się spinnera, ponieważ ProgressBar rysowany jest na wierzchu.

Przykład 3: Kontener fragmentów

FrameLayout jako standardowy kontener dla FragmentTransaction. Aktywność zastępuje fragmenty wewnątrz tego kontenera w zależności od nawigacji.

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 jako kontener fragmentów — najlżejszy sposób obsługi Fragment Navigation. FragmentContainerView (dziedziczący po FrameLayout) jest zalecany w Navigation Component 2.4+, ale prosty FrameLayout pozostaje prawidłowy dla ręcznych FragmentTransaction. Kluczową zaletą jest to, że FragmentTransaction.replace() całkowicie zastępuje zawartość, nie wpływając na Activity.

Kiedy używać FrameLayout

FrameLayout jest optymalny dla czterech scenariuszy: kontener fragmentów (FragmentContainerView lub FrameLayout), nakładka ładowania (ProgressBar nad treścią), etykiety na kartach (znacznik na obrazie), kontener zastępczy dla ViewStub (leniwe ładowanie).

Nie nadaje się do: złożonego pozycjonowania wielu elementów (użyj ConstraintLayout), list sekwencyjnych (LinearLayout lub RecyclerView), dynamicznych układów ze zmianą kolejności elementów.

FrameLayout jako główny element ekranu — zła praktyka, jeśli ekran zawiera więcej niż 2–3 elementy. Jako główny kontener używaj ConstraintLayout — daje więcej kontroli nad pozycjonowaniem bez utraty wydajności. FrameLayout używaj tylko dla bloków potomnych, gdzie potrzebne jest nakładanie lub placeholder.

Często zadawane pytania

Jaka jest różnica między FrameLayout a ConstraintLayout?

FrameLayout — minimalistyczny kontener bez systemu pozycjonowania (tylko layout_gravity), przeznaczony do nakładania elementów. ConstraintLayout — pełnoprawny system układu z ograniczeniami, łańcuchami, barierami, procentowymi rozmiarami i obsługą MotionLayout. FrameLayout jest szybszy dla prostych przypadków (1 child lub overlay); ConstraintLayout jest obowiązkowy dla złożonych układów. Wybór: FrameLayout do nakładki ładowania i kontenera fragmentów; ConstraintLayout do wszystkiego innego.

Jak sprawić, aby FrameLayout zajmował tylko miejsce największego child?

Ustaw FrameLayout rozmiar wrap_content na potrzebnej osi (android:layout_width="wrap_content" i/lub android:layout_height="wrap_content"). W tym przypadku FrameLayout dostosuje się do rozmiaru największego elementu potomnego. Jeśli wszystkie dzieci są mniejsze niż FrameLayout, nadmiarowa przestrzeń pozostanie pusta. Do precyzyjnej kontroli używaj match_parent ze stałymi padding.

Dlaczego elementy w FrameLayout nakładają się na siebie?

To normalne zachowanie FrameLayout — nie rozdziela on dzieci w przestrzeni, lecz rysuje je kolejno jedno na drugim. Jeśli chcesz, aby elementy nie nakładały się, użyj innego kontenera (LinearLayout, ConstraintLayout). Do częściowego nakładania z kontrolą kolejności rysowania używaj layout_gravity do przesunięcia i elevation dla Z-order.

Co jest szybsze: FrameLayout czy ConstraintLayout?

FrameLayout jest szybszy dla maksymalnie prostych przypadków — jeden element potomny, bez złożonego pozycjonowania. FrameLayout wykonuje onMeasure w minimalnym czasie, nie obliczając ograniczeń. Jednak różnica jest zauważalna tylko przy setkach powtórzeń (RecyclerView na dziesiątkach tysięcy elementów). Dla zwykłego ekranu (1–3 FrameLayout) różnica wynosi mikrosekundy i nie wpływa na UX. ConstraintLayout to uniwersalny wybór dla 95% zadań.

Podsumowanie

  • FrameLayout — najprostsza ViewGroup Androida do nakładania elementów i kontenerów zastępczych z minimalnym narzutem.
  • Nakładanie warstw — każdy nowy child rysowany jest nad poprzednim; ostatni zadeklarowany w XML jest najwyżej.
  • Foreground — drawable nad wszystkimi dziećmi do efektów nakładkowych, maskowania i animacji ripple.
  • measureAllChildren — wyłączenie (false) wyklucza elementy GONE z obliczania rozmiaru, przyspieszając renderowanie o 20–60%.
  • layout_gravity — jedyny mechanizm pozycjonowania: top, bottom, left, right, center i ich kombinacje.
  • Kontener fragmentów — najczęstszy przypadek użycia: FrameLayout (lub FragmentContainerView) dla FragmentTransaction.replace().
  • Wydajność — najszybszy kontener dla 1 child; dla złożonych układów ustępuje ConstraintLayout.

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt

Przeczytaj również