Вивчіть ключові поняття FrameLayout — найпростіша ViewGroup в Android SDK, призначена для розміщення одного дочірнього елемента (зазвичай) або накладання кількох елементів один на одного. FrameLayout зручний для контейнерів-заглушок, фрагментів, індикаторів завантаження та елементів переднього плану. Він не керує розташуванням дітей — кожен наступний елемент малюється поверх попереднього, а їх позиція визначається layout_gravity (left, top, right, bottom, center). Базові сценарії описані в FrameLayout API Reference.
Головне
FrameLayout — найпростіша ViewGroup в Android SDK, призначена для блокування області екрана та відображення одного дочірнього view (або накладання кількох). На відміну від LinearLayout (послідовне розміщення) та RelativeLayout (відносне позиціонування), FrameLayout не змінює позиції дітей — кожен новий child поміщається в лівий верхній кут (0,0) за замовчуванням і малюється поверх попереднього.
FrameLayout з'явився в API Level 1 і залишається найлегшим контейнером Android: він не перевизначає onMeasure складною логікою та виконує мінімальну кількість операцій layout. Згідно з Android Performance Blog, FrameLayout виконує onLayout за один прохід і практично не додає накладних витрат порівняно з розміщенням View безпосередньо. Це робить його ідеальним вибором для контейнерів, де важлива швидкість: макети елементів RecyclerView (в парі з ConstraintLayout для позиціонування), контейнери Fragment, шари накладання.
Розмір FrameLayout за замовчуванням визначається найбільшим дочірнім елементом (якщо не задано match_parent). Якщо жоден child не вказано, FrameLayout згортається до (0,0). Атрибут android:measureAllChildren (розділ нижче) змінює цю поведінку.
FrameLayout успадковується від ViewGroup і є прямим батьком багатьох спеціалізованих контейнерів: FragmentContainerView (фрагменти), CardView (картки з тінню), ScrollView (один child), NestedScrollView. При створенні Activity з навігацією за фрагментами стандартний шаблон Android Studio використовує FrameLayout (або FragmentContainerView) як кореневий контейнер для фрагментів.
android:foreground — атрибут FrameLayout, що задає drawable, який малюється поверх усіх дочірніх елементів. На відміну від background (під дітьми), foreground відображається над вмістом і може бути прозорим. Використовується для: ефектів накладання при натисканні (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 забезпечує накладання без зміни позиції контенту — текст не зсувається при появі спіннера, оскільки 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), loading overlay (ProgressBar поверх контенту), карткові мітки (мітка на зображенні), контейнер-заглушка для ViewStub (ліниве завантаження).
Не підходить для: складного позиціонування кількох елементів (використовуйте ConstraintLayout), послідовних списків (LinearLayout або RecyclerView), динамічних макетів зі зміною порядку елементів.
FrameLayout як кореневий елемент екрана — погана практика, якщо екран містить більше 2–3 елементів. Для кореневого контейнера використовуйте ConstraintLayout — він дає більше контролю над позиціонуванням без втрати продуктивності. FrameLayout використовуйте лише для дочірніх блоків, де потрібно накладання або заглушка.
Поширені запитання
FrameLayout — мінімалістичний контейнер без системи позиціонування (тільки layout_gravity), призначений для накладання елементів. ConstraintLayout — повноцінна система верстки з констрейнтами, ланцюгами, бар'єрами, відсотковими розмірами та підтримкою MotionLayout. FrameLayout швидший для простих випадків (1 child або overlay); ConstraintLayout обов'язковий для складних макетів. Вибір: FrameLayout для loading overlay та fragment-container; 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-порядку.
FrameLayout швидший для максимально простих випадків — один дочірній елемент, без складного позиціонування. FrameLayout виконує onMeasure за мінімальний час, не обчислюючи констрейнтів. Однак різниця помітна лише при сотнях повторень (RecyclerView на десятках тисяч елементів). Для звичайного екрана (1–3 FrameLayout) різниця в мікросекундах і не впливає на UX. ConstraintLayout — універсальний вибір для 95% завдань.
Підсумки
Ми розробимо мобільний застосунок під ключ
IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.
Читайте також