ماهیت RelativeLayout را توضیح میدهیم — ViewGroup در Android SDK برای موقعیتیابی عناصر فرزند نسبت به یکدیگر یا نسبت به ظرف والد. برخلاف LinearLayout که عناصر را بهطور کاملاً متوالی میچیند، RelativeLayout به شما اجازه میدهد هر عنصری را در چپ، راست، بالا، پایین یا مرکز نسبت به هر عنصر دیگری بر اساس ID آن قرار دهید. این باعث میشود RelativeLayout برای طرحهای همپوشان و پیچیده بدون تودرتو مناسب باشد. قواعد اصلی در مستندات Android Developers شرح داده شده است.
نکات کلیدی
RelativeLayout — ViewGroup که از API Level 1 در Android SDK وجود دارد و عناصر فرزند را از طریق قواعد اعلامی (layout rules) نسبت به والد یا سایر عناصر فرزند موقعیتیابی میکند. هر قاعده با ویژگی XML مانند android:layout_above، android:layout_below، android:layout_toLeftOf با مقدار ID عنصر هدف تعیین میشود.
پیش از ظهور RelativeLayout، توسعهدهندگان مجبور به استفاده از LinearLayoutهای تودرتو برای هر موقعیتیابی غیراستاندارد بودند — این امر منجر به تودرتویی عمیق و رندر کند میشد. RelativeLayout این مشکل را با ارائه موقعیتیابی نسبی در یک سطح از سلسلهمراتب حل کرد. با این حال، انعطافپذیری آن در مقایسه با ConstraintLayout مدرن محدود است: RelativeLayout از زنجیرهها، موانع، راهنماها و اندازههای درصدی پشتیبانی نمیکند.
RelativeLayout دو ویژگی کلیدی دارد: یک پیمایش onMeasure (برخلاف LinearLayout با weight که به دو پیمایش نیاز دارد) و وابستگی به ترتیب اعلام — اگر عنصر A به عنصر B ارجاع دهد و B پس از A اعلام شده باشد، B باید در زمان اندازهگیری A اندازه مشخصی داشته باشد. طبق Android Developers Guide (2024)، RelativeLayout اندازهگیری را در یک پیمایش انجام میدهد اگر همه قواعد به عناصر از پیش اندازهگیری شده ارجاع دهند. در غیر این صورت، پیمایش دوم مورد نیاز است که عملکرد را کاهش میدهد.
RelativeLayout برای طرحهای ساده با ۳–۷ عنصر که نیاز به موقعیتیابی نسبی دارند (برچسب بالای دکمه، آیکون سمت راست متن، پنل پایین صفحه) مناسب است. برای پروژههای جدید ConstraintLayout توصیه میشود، اما RelativeLayout همچنان بهطور گسترده در کدهای قدیمی و کتابخانهها استفاده میشود.
RelativeLayout از دو نوع قاعده استفاده میکند: قواعد relative (موقعیتیابی نسبت به عنصر دیگر) و قواعد align (اتصال به والد). هر عنصر فرزند میتواند تعداد نامحدودی قاعده داشته باشد، اما قواعد متناقض (مثلاً alignParentTop و below عنصر دیگر) به نفع آخرین قاعده اعلام شده در ویژگی حل میشوند.
قواعد relative:
- android:layout_above="@id/target" — لبه پایینی عنصر به لبه بالایی target متصل میشود.
- android:layout_below="@id/target" — لبه بالایی عنصر به لبه پایینی target متصل میشود.
- android:layout_toLeftOf="@id/target" — لبه راست به لبه چپ target متصل میشود.
- android:layout_toRightOf="@id/target" — لبه چپ به لبه راست target متصل میشود.
- android:layout_toStartOf="@id/target" — معادل toLeftOf برای بومیسازی RTL.
- android:layout_toEndOf="@id/target" — معادل toRightOf برای RTL.
قواعد align (به والد):
- android:layout_alignParentTop="true" — لبه بالایی عنصر با لبه بالایی والد منطبق میشود.
- android:layout_alignParentBottom="true" — لبه پایینی با لبه پایینی والد منطبق میشود.
- android:layout_alignParentLeft="true" — لبه چپ با لبه چپ والد منطبق میشود.
- android:layout_alignParentRight="true" — لبه راست با لبه راست والد منطبق میشود.
- android:layout_alignParentStart و android:layout_alignParentEnd — برای RTL.
قواعد align به عناصر دیگر:
- android:layout_alignTop="@id/target" — بالای عنصر با بالای target منطبق میشود.
- android:layout_alignBottom، android:layout_alignLeft، android:layout_alignRight، android:layout_alignStart، android:layout_alignEnd — به همین ترتیب.
- android:layout_alignBaseline="@id/target" — تراز بر اساس خط پایه متن (برای ردیفهایی با اندازه قلم متفاوت مفید است).
مرکزچینی در RelativeLayout با سه ویژگی تعیین میشود: android:layout_centerInParent="true" (مرکز والد در هر دو محور)، android:layout_centerHorizontal="true" (مرکز افقی) و android:layout_centerVertical="true" (مرکز عمودی). مرکزچینی با سایر قواعد سازگار است: یک عنصر میتواند افقی مرکزچین شود و همزمان به لبه پایینی والد متصل باشد.
ترتیب همپوشانی (Z-order) در RelativeLayout توسط ترتیب اعلام عناصر در XML تعیین میشود. اولین عنصر اعلام شده اولین بار رسم میشود (پایینتر خواهد بود)، آخرین عنصر آخرین بار رسم میشود (بالاتر خواهد بود). اگر نیاز به تغییر ترتیب همپوشانی بدون تغییر XML دارید، از android:elevation (از API 21 به بعد) استفاده کنید — عناصر با elevation بالاتر روی سطح رسم میشوند. برای نسخههای پایینتر از API 21، ترتیب همپوشانی فقط با ترتیب اعلام تنظیم میشود.
مهم: RelativeLayout از ویژگی android:elevation برای والد پشتیبانی نمیکند — هر عنصر elevation خود را مستقل مدیریت میکند. در صورت تضاد بین قواعد موقعیتیابی و elevation (مثلاً عناصر همپوشان)، elevation برای رسم اولویت دارد، اما برای موقعیتیابی نه — عنصری با elevation بالاتر میتواند از نظر بصری عنصر دیگر را بپوشاند، حتی اگر قواعد layout آن را «پشت» قرار دهند.
آواتار در مرکز بالا، نام زیر آواتار، وضعیت زیر نام، دکمه اقدام در پایین صفحه. همه عناصر از قواعد relative برای اتصال متوالی استفاده میکنند.
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/avatar"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_centerHorizontal="true"
android:layout_marginTop="32dp"
android:src="@drawable/avatar_placeholder" />
<TextView
android:id="@+id/user_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/avatar"
android:layout_centerHorizontal="true"
android:layout_marginTop="12dp"
android:text="ایوان ایوانوف"
android:textSize="20sp"
android:textStyle="bold" />
<TextView
android:id="@+id/user_status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/user_name"
android:layout_centerHorizontal="true"
android:text="آنلاین"
android:textColor="@color/green" />
<Button
android:id="@+id/edit_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="24dp"
android:text="ویرایش پروفایل" />
</RelativeLayout>
آواتار به بالا از طریق marginTop + centerHorizontal متصل است، نام — زیر آواتار از طریق layout_below، وضعیت — زیر نام، دکمه — به لبه پایینی والد از طریق alignParentBottom. همه عناصر مستقل از یکدیگر هستند، زنجیره یا تودرتو وجود ندارد.
آیکون با نشان قرمز (دایره با عدد) در گوشه بالا سمت راست. نشان نسبت به آیکون از طریق align به لبههای آن با margin منفی برای همپوشانی موقعیتیابی میشود.
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/icon"
android:layout_width="48dp"
android:layout_height="48dp"
android:src="@drawable/ic_notification" />
<TextView
android:id="@+id/badge"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_alignTop="@+id/icon"
android:layout_alignRight="@+id/icon"
android:layout_marginTop="-6dp"
android:layout_marginRight="-6dp"
android:gravity="center"
android:background="@drawable/badge_background"
android:text="3"
android:textColor="@android:color/white"
android:textSize="10sp" />
</RelativeLayout>
نشان به لبه بالایی و راستی آیکون متصل است. margin منفی (۶- dp) نشان را به بیرون میکشاند و اثر همپوشانی لبه آیکون را ایجاد میکند. این یک الگوی محبوب برای اعلانها است که بدون RelativeLayout به FrameLayout یا رسم سفارشی نیاز داشت.
فرم ورود: لوگو در مرکز بالا، فیلد ایمیل زیر آن، فیلد رمز زیر ایمیل، دکمه «ورود» زیر رمز، لینک «ثبتنام» به پایین چسبیده. همه عناصر به صورت متوالی از طریق layout_below متصل شدهاند.
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="24dp">
<TextView
android:id="@+id/logo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="48dp"
android:text="MyApp"
android:textSize="32sp"
android:textStyle="bold" />
<EditText
android:id="@+id/email_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/logo"
android:layout_marginTop="32dp"
android:hint="Email" />
<EditText
android:id="@+id/password_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/email_input"
android:layout_marginTop="16dp"
android:hint="رمز عبور"
android:inputType="textPassword" />
<Button
android:id="@+id/login_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/password_input"
android:layout_marginTop="24dp"
android:text="ورود" />
<TextView
android:id="@+id/register_link"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="16dp"
android:text="حساب ندارید؟ ثبت نام کنید"
android:textColor="@color/primary" />
</RelativeLayout>
صفحه از ۵ عنصر در یک سطح از سلسلهمراتب استفاده میکند. جریان از بالا به پایین (لوگو → ایمیل → رمز → دکمه) از طریق layout_below تضمین شده است و لینک از طریق alignParentBottom به پایین چسبیده است. برای همان عملکرد، LinearLayout به دو ظرف تودرتو نیاز داشت (یکی برای گروه بالایی، دومی برای لینک با weight).
مقایسه دو ViewGroup برای موقعیتیابی نسبی: RelativeLayout (کلاسیک، API 1+) و ConstraintLayout (مدرن، Jetpack). معیارها: انعطافپذیری، عملکرد، پشتیبانی RTL و تطبیقپذیری.
| ویژگی | RelativeLayout | ConstraintLayout |
|---|---|---|
| اندازههای درصدی | خیر (فقط ثابت و match_parent) | بله (width_percent، height_percent، guideline_percent) |
| پشتیبانی RTL | از طریق start/end (API 17+) | داخلی |
| Chain / زنجیرهها | خیر | بله (spread، spread_inside، packed) |
| Barrier / Group / Flow | خیر | بله (کمککنندههای مجازی) |
| انیمیشنهای MotionLayout | خیر | بله |
| پیمایشهای onMeasure | ۱ (بدون چرخه وابستگی) | ۲ (همیشه، اما بهینهشده) |
| مرکزچینی | centerInParent، centerHorizontal، centerVertical | از طریق bias (۰.۰–۱.۰) با محدودیتهای مخالف |
| زمان استفاده | کد قدیمی، طرحهای ساده با ۳–۷ عنصر | پروژههای جدید، صفحههای پیچیده، طرحهای تطبیقی |
RelativeLayout تقریباً از همه نظر از ConstraintLayout پایینتر است، به جز یک مورد: از API 1 در Android SDK تعبیه شده است و به وابستگی اضافی نیاز ندارد. برای پروژههایی که هنوز از minSdk پایینتر از API 14 (Android 4.0) استفاده میکنند، RelativeLayout تنها گزینه استاندارد برای موقعیتیابی نسبی است. در تمام موارد دیگر، Google ConstraintLayout را توصیه میکند.
سوالات متداول
محتملترین دلیل — نبود تعداد کافی قواعد موقعیتیابی. هر عنصر در RelativeLayout باید حداقل یک قاعده افقی (alignParentLeft، toRightOf، centerHorizontal) و یک قاعده عمودی (alignParentTop، below، centerVertical) داشته باشد. اگر قاعدهای نباشد، عنصر در موقعیت (۰,۰) قرار میگیرد و ممکن است زیر عناصر دیگر یا خارج از صفحه پنهان شود. دلیل دوم — وابستگی چرخهای (عنصر A به B متصل است، B به A متصل است) که منجر به رفتار غیرقابل پیشبینی میشود.
از ویژگی android:layout_centerInParent="true" استفاده کنید. این عنصر را در هر دو محور همزمان مرکزچین میکند. اگر فقط افقی نیاز دارید — android:layout_centerHorizontal="true"، فقط عمودی — android:layout_centerVertical="true". مرکزچینی همراه با margin کار میکند — عنصر به اندازه حاشیه مشخص شده از مرکز جابهجا میشود.
میتوان، اما توصیه نمیشود. RelativeLayout در صورت وجود وابستگیهای چرخهای دو پیمایش onMeasure انجام میدهد که در لیستهای RecyclerView ۱۵–۳۰٪ کندتر از ConstraintLayout است. برای طرحهای آیتم RecyclerView از ConstraintLayout استفاده کنید — این سلسلهمراتب تخت با حداقل زمان اندازهگیری فراهم میکند. اگر RelativeLayout در پروژه قدیمی استفاده شده است، مطمئن شوید عناصر وابستگی چرخهای ایجاد نمیکنند و FPS اسکرول را از طریق Profile GPU Rendering اندازهگیری کنید.
android:layout_margin حاشیه را از همه طرف همزمان تعیین میکند. android:layout_marginTop — فقط از بالا. ویژگی خاصتر اولویت دارد: اگر هم layout_margin (۱۶dp) و هم layout_marginTop (۸dp) تنظیم شده باشند، حاشیه بالایی ۸dp خواهد بود. در RelativeLayout، margin نسبت به محدودیت (constraint) کار میکند، نه نسبت به عنصر مجاور: layout_marginTop با layout_below="@id/target" — این فاصله از لبه بالایی عنصر تا لبه پایینی target است.
خلاصه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید