Научите кључне концепте FrameLayout-а — најједноставније ViewGroup у Android SDK-у, намењене за смештање једног подређеног елемента (обично) или постављање више елемената један на други. FrameLayout је згодан за placeholder контејнере, фрагменте, индикаторе учитавања и елементе у предњем плану. Он не управља распоредом деце — сваки следећи елемент се црта изнад претходног, а њихова позиција се одређује путем layout_gravity (left, top, right, bottom, center). Основни сценарији су описани у FrameLayout API Reference-у.
Главни закључци
FrameLayout је најједноставнија ViewGroup у Android SDK-у, дизајнирана за блокирање области екрана и приказ једног подређеног приказа (или постављање више њих један преко другог). За разлику од LinearLayout-а (секвенцијални распоред) и RelativeLayout-а (релативно позиционирање), FrameLayout не мења положај деце — сваки нови child се подразумевано поставља у горњи леви угао (0,0) и црта се изнад претходног.
FrameLayout се појавио у API Level 1 и остаје најлакши Android контејнер: не преписује onMeasure сложеном логиком и извршава минималан број layout операција. Према Android Performance Blog-у, FrameLayout извршава onLayout у једном пролазу и практично не додаје додатне трошкове у поређењу са директним постављањем View-а. То га чини идеалним избором за контејнере где је брзина важна: layout-и ставки RecyclerView-а (у пару са ConstraintLayout-ом за позиционирање), контејнери фрагмената, overlay слојеви.
Подразумевана величина FrameLayout-а одређује се највећим подређеним елементом (ако није подешен match_parent). Ако ниједан child није наведен, FrameLayout се скупља на (0,0). Атрибут android:measureAllChildren (одељак испод) мења ово понашање.
FrameLayout наслеђује ViewGroup и директни је родитељ многих специјализованих контејнера: FragmentContainerView (фрагменти), CardView (картице сенком), ScrollView (са једним child-ом), NestedScrollView. Приликом креирања Activity са Fragment навигацијом, стандардни Android Studio шаблон користи FrameLayout (или FragmentContainerView) као основни контејнер за фрагменте.
android:foreground — атрибут FrameLayout-а који поставља drawable који се црта изнад свих подређених елемената. За разлику од background-а (испод деце), foreground се приказује изнад садржаја и може бити провидан. Користи се за: overlay ефекте при притиску (ripple преко ?attr/selectableItemBackground), маскирање слика, приказ статусних индикатора (квачица за избор изнад слике).
Foreground подржава стандардне drawable ресурсе: ColorDrawable, ShapeDrawable, RippleDrawable, LayerDrawable. Од API 23+ доступан је android:foregroundGravity за позиционирање foreground-а (fill, center, top, bottom). У режиму „испуни" (fill), foreground се растеже на цео FrameLayout; у режиму center — црта се у центру.
android:measureAllChildren — логички атрибут (подразумевано true) који одређује да ли треба мерити све подређене елементе при израчунавању величине FrameLayout-а. Ако је true (подразумевано), FrameLayout узима у обзир величине све деце, укључујући GONE (величине 0). Ако је false, FrameLayout мери само видљиву (VISIBLE) и невидљиву (INVISIBLE) децу — GONE елементи се искључују из прорачуна. Према Google I/O 2019, искључивање measureAllChildren за контејнере са великим бројем GONE елемената (нпр. листе са пребацивањем видљивости) убрзава почетно приказивање за 20–60%.
android:layout_gravity — атрибут подређеног елемента FrameLayout-а (и других ViewGroup-а) који одређује његов положај унутар контејнера. У FrameLayout-у, layout_gravity је једини начин управљања положајем подређеног елемента, јер FrameLayout не пружа сопствена правила позиционирања (као RelativeLayout) или смер (као LinearLayout).
Могуће вредности: top, bottom, left, right, center, center_horizontal, center_vertical, fill, fill_horizontal, fill_vertical, clip_horizontal, clip_vertical. Комбинују се помоћу |: android:layout_gravity="bottom|center_horizontal" — елемент је прилепљен уз доњу ивицу и центриран хоризонтално. За елементе чија је величина мања од FrameLayout-а, layout_gravity одређује њихов положај у слободном простору.
Ако layout_gravity није подешен, подразумевано се елемент поставља у горњи леви угао (top|left). За FrameLayout који садржи више деце, свако може имати свој layout_gravity — један елемент може бити у горњем левом углу, други у доњем десном, трећи у центру. Ово омогућава креирање једноставних преклапања (нпр. крстић за затварање изнад слике).
android:gravity (родитељски атрибут) поравнава садржај унутар FrameLayout-а — на пример, текст унутар TextView-а. android:layout_gravity (подређени атрибут) поравнава сам елемент унутар FrameLayout-а. У контексту FrameLayout-а, gravity одређује како су деца подразумевано распоређена (аналогно layout_gravity за сву децу одједном), али layout_gravity сваког конкретног елемента замењује родитељску вредност.
Слика и текстуална ознака у доњем десном углу. FrameLayout садржи ImageView преко целог екрана и TextView са layout_gravity="bottom|end" за позиционирање изнад.
<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 заузима цео FrameLayout (200dp висине). TextView са layout_gravity="bottom|end" поставља се у доњи десни угао изнад слике. elevation=2dp додаје сенку испод ознаке, визуелно је одвајајући од слике. Ово је минимални пример који би у LinearLayout-у захтевао угнежђени контејнер или прилагођени код.
Екран са садржајем и прогрес баром у центру који се појављује при учитавању. FrameLayout садржи два елемента: садржај и ProgressBar са visibility="gone" (пребацује се у коду).
<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="Учитани садржај"
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 је подразумевано сакривен (gone). При почетку учитавања, у коду се позива findViewById(R.id.loading_spinner).visibility = View.VISIBLE — спинер се појављује у центру изнад садржаја. Након учитавања — .visibility = View.GONE. FrameLayout обезбеђује преклапање без промене положаја садржаја — текст се не помера при појави спинерa, јер се ProgressBar црта изнад.
FrameLayout као стандардни контејнер за FragmentTransaction. Активност замењује фрагменте унутар овог контејнера у зависности од навигације.
<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 као контејнер фрагмената — најлакши начин подршке за Fragment Navigation. FragmentContainerView (наследник FrameLayout-а) се препоручује са Navigation Component 2.4+, али обични FrameLayout остаје валидан за ручне FragmentTransaction. Кључна предност — FragmentTransaction.replace() у потпуности замењује садржај без утицаја на Activity.
FrameLayout је оптималан за четири сценарија: контејнер фрагмената (FragmentContainerView или FrameLayout), overlay за учитавање (ProgressBar изнад садржаја), ознаке на картицама (знак на слици), placeholder контејнер за ViewStub (лењо учитавање).
Није погодан за: сложено позиционирање више елемената (користите ConstraintLayout), секвенцијалне листе (LinearLayout или RecyclerView), динамичке распореде са променом редоследа елемената.
FrameLayout као коренски елемент екрана — лоша пракса ако екран садржи више од 2–3 елемента. За коренски контејнер користите ConstraintLayout — пружа више контроле над позиционирањем без губитка перформанси. FrameLayout користите само за подређене блокове где је потребно преклапање или placeholder.
Често постављана питања
FrameLayout — минималистички контејнер без система позиционирања (само layout_gravity), намењен за преклапање елемената. ConstraintLayout — потпун систем распореда са констрејнтима, ланцима, баријерама, процентуалним величинама и подршком за MotionLayout. FrameLayout је бржи за једноставне случајеве (1 child или overlay); ConstraintLayout је обавезан за сложене распореде. Избор: FrameLayout за overlay учитавања и контејнер фрагмената; ConstraintLayout за све остало.
Подесите величину FrameLayout-а на wrap_content на потребној оси (android:layout_width="wrap_content" и/или android:layout_height="wrap_content"). У овом случају, FrameLayout ће се прилагодити величини највећег подређеног елемента. Ако су сва деца мања од FrameLayout-а, вишак простора остаће празан. За прецизну контролу користите match_parent са фиксним padding-ом.
Ово је нормално понашање FrameLayout-а — он не распоређује децу у простору, већ их црта узастопно једно преко другог. Ако желите да се елементи не преклапају, користите други контејнер (LinearLayout, ConstraintLayout). За делимично преклапање са контролом редоследа цртања користите layout_gravity за померање и elevation за Z-order.
FrameLayout је бржи за максимално једноставне случајеве — један подређени елемент, без сложеног позиционирања. FrameLayout извршава onMeasure у минималном времену, без израчунавања констрејнти. Међутим, разлика је приметна само при стотинама понављања (RecyclerView са десетинама хиљада елемената). За обичан екран (1–3 FrameLayout), разлика је у микросекундама и не утиче на UX. ConstraintLayout је универзални избор за 95% задатака.
Резиме
Развићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође