مفاهیم کلیدی FrameLayout — سادهترین ViewGroup در Android SDK، طراحیشده برای قرار دادن یک عنصر فرزند (معمولاً) یا قرار دادن چند عنصر روی هم. FrameLayout برای کانتینرهای placeholder، fragmentها، نشانگرهای بارگذاری و عناصر پیشزمینه مناسب است. این ViewGroup مکان فرزندان را مدیریت نمیکند — هر عنصر بعدی روی عنصر قبلی رسم میشود و موقعیت آنها توسط layout_gravity (left, top, right, bottom, center) تعیین میشود. سناریوهای پایه در FrameLayout API Reference شرح داده شدهاند.
نکات اصلی
FrameLayout سادهترین ViewGroup در Android SDK است که برای مسدود کردن ناحیه صفحه و نمایش یک view فرزند (یا قرار دادن چندین view روی هم) طراحی شده. برخلاف LinearLayout (قرارگیری ترتیبی) و RelativeLayout (موقعیتدهی نسبی)، FrameLayout موقعیت فرزندان را تغییر نمیدهد — هر child جدید بهطور پیشفرض در گوشه بالا سمت چپ (۰,۰) قرار میگیرد و روی قبلی رسم میشود.
FrameLayout از API Level 1 وجود داشته و سبکترین کانتینر Android باقی مانده است: متد onMeasure را با منطق پیچیده بازنویسی نمیکند و حداقل تعداد عملیات layout را انجام میدهد. طبق Android Performance Blog، FrameLayout onLayout را در یک پاس اجرا میکند و عملاً نسبت به قرار دادن مستقیم View هیچ سرباری اضافه نمیکند. این使它 را به گزینهای ایدهآل برای کانتینرهایی تبدیل میکند که سرعت در آنها مهم است: layoutهای item در RecyclerView (همراه با ConstraintLayout برای موقعیتدهی)، کانتینرهای fragment، لایههای overlay.
اندازه پیشفرض FrameLayout توسط بزرگترین عنصر فرزند تعیین میشود (اگر match_parent تنظیم نشده باشد). اگر هیچ childای مشخص نشود، FrameLayout به (۰,۰) جمع میشود. ویژگی android:measureAllChildren (بخش زیر) این رفتار را تغییر میدهد.
FrameLayout از ViewGroup ارثبری میکند و والد مستقیم بسیاری از کانتینرهای تخصصی است: FragmentContainerView (fragmentها)، CardView (کارتهای با سایه)، ScrollView (با یک child)، NestedScrollView. هنگام ایجاد Activity با ناوبری Fragment، قالب استاندارد Android Studio از FrameLayout (یا FragmentContainerView) بهعنوان کانتینر اصلی fragmentها استفاده میکند.
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 (با اندازه ۰) را در نظر میگیرد. اگر false، FrameLayout فقط فرزندان VISIBLE و INVISIBLE را اندازهگیری میکند — عناصر GONE از محاسبه حذف میشوند. طبق Google I/O 2019، غیرفعال کردن measureAllChildren برای کانتینرهایی با تعداد زیادی عنصر GONE (مثلاً لیستهایی با قابلیت تغییر visibility) رندر اولیه را ۲۰–۶۰٪ تسریع میکند.
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 خاص خود را داشته باشند — یک عنصر میتواند در گوشه بالا سمت چپ باشد، دیگری در گوشه پایین سمت راست، سومی در مرکز. این امکان ایجاد overlayهای ساده را فراهم میکند (مثلاً علامت ضربدر بستن روی تصویر).
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 (ارتفاع ۲۰۰dp) را اشغال میکند. 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 فراخوانی میشود — spinner در مرکز روی محتوا ظاهر میشود. پس از بارگذاری — .visibility = View.GONE. FrameLayout لایهبندی را بدون تغییر موقعیت محتوا تضمین میکند — متن هنگام ظاهر شدن spinner جابهجا نمیشود، زیرا ProgressBar روی آن رسم میشود.
FrameLayout بهعنوان کانتینر استاندارد برای FragmentTransaction. Activity بسته به ناوبری fragmentها را درون این کانتینر جایگزین میکند.
<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 — سبکترین روش پشتیبانی از Fragment Navigation. FragmentContainerView (وارث FrameLayout) در Navigation Component 2.4+ توصیه میشود، اما FrameLayout ساده برای FragmentTransaction دستی معتبر باقی میماند. مزیت کلیدی — FragmentTransaction.replace() محتوا را کاملاً جایگزین میکند بدون اینکه بر Activity تأثیر بگذارد.
FrameLayout برای چهار سناریو بهینه است: کانتینر fragmentها (FragmentContainerView یا FrameLayout)، overlay بارگذاری (ProgressBar روی محتوا)، برچسبهای کارت (نشان روی تصویر)، کانتینر placeholder برای ViewStub (بارگذاری تنبل).
مناسب نیست برای: موقعیتدهی پیچیده چند عنصر (از ConstraintLayout استفاده کنید)، لیستهای ترتیبی (LinearLayout یا RecyclerView)، layoutهای پویا با تغییر ترتیب عناصر.
FrameLayout بهعنوان عنصر ریشه صفحه — اگر صفحه بیش از ۲–۳ عنصر داشته باشد، روش بدی است. برای کانتینر ریشه از ConstraintLayout استفاده کنید — کنترل بیشتری روی موقعیتدهی بدون کاهش عملکرد میدهد. FrameLayout را فقط برای بلوکهای فرزندی که نیاز به لایهبندی یا placeholder دارند استفاده کنید.
سوالات متداول
FrameLayout — کانتینر مینیمال بدون سیستم موقعیتدهی (فقط layout_gravity)، طراحیشده برای لایهبندی عناصر. ConstraintLayout — یک سیستم layout کامل با constraintها، زنجیرها، مانعها، اندازههای درصدی و پشتیبانی از MotionLayout. FrameLayout برای موارد ساده (۱ child یا overlay) سریعتر است؛ ConstraintLayout برای layoutهای پیچیده ضروری است. انتخاب: FrameLayout برای overlay بارگذاری و کانتینر fragment؛ 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 را در حداقل زمان انجام میدهد و constraintها را محاسبه نمیکند. اما تفاوت فقط در صدها تکرار (RecyclerView با دهها هزار عنصر) قابل توجه است. برای صفحه معمولی (۱–۳ FrameLayout) تفاوت در میکروثانیههاست و بر UX تأثیر نمیگذارد. ConstraintLayout انتخاب جهانی برای ۹۵٪ وظایف است.
خلاصه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید