طرحبندیها در نماها
یک طرحبندی، ساختار رابط کاربری را در برنامه شما، مانند یک فعالیت ، تعریف میکند. همه عناصر موجود در طرحبندی با استفاده از سلسله مراتبی از اشیاء View و ViewGroup ساخته میشوند. یک View معمولاً چیزی را ترسیم میکند که کاربر میتواند آن را ببیند و با آن تعامل داشته باشد. ViewGroup یک ظرف نامرئی است که ساختار طرحبندی را برای View و سایر اشیاء ViewGroup تعریف میکند، همانطور که در شکل 1 نشان داده شده است.

اشیاء View اغلب Widgets نامیده میشوند و میتوانند یکی از زیرکلاسهای زیادی مانند Button یا TextView باشند. اشیاء ViewGroup معمولاً layouts نامیده میشوند و میتوانند یکی از انواع زیادی باشند که ساختار layout متفاوتی مانند LinearLayout یا ConstraintLayout ارائه میدهند.
شما میتوانید یک طرحبندی (layout) را به دو روش اعلان کنید:
- عناصر رابط کاربری را در XML تعریف کنید. اندروید یک واژگان XML سرراست ارائه میدهد که با کلاسها و زیرکلاسهای
View، مانند کلاسهای مربوط به ویجتها و طرحبندیها، مطابقت دارد. همچنین میتوانید از ویرایشگر طرحبندی اندروید استودیو برای ساخت طرحبندی XML خود با استفاده از رابط کشیدن و رها کردن استفاده کنید. - عناصر طرحبندی را در زمان اجرا نمونهسازی کنید. برنامه شما میتواند اشیاء
ViewوViewGroupرا ایجاد کرده و ویژگیهای آنها را به صورت برنامهنویسی دستکاری کند.
تعریف رابط کاربری (UI) در XML به شما این امکان را میدهد که نحوهی نمایش برنامهی خود را از کدی که رفتار آن را کنترل میکند، جدا کنید. استفاده از فایلهای XML همچنین ارائهی طرحبندیهای مختلف برای اندازهها و جهتهای مختلف صفحه نمایش را آسانتر میکند. این موضوع در بخش «پشتیبانی از اندازههای مختلف صفحه نمایش» بیشتر مورد بحث قرار گرفته است.
چارچوب اندروید به شما این انعطافپذیری را میدهد که از یک یا هر دوی این روشها برای ساخت رابط کاربری برنامه خود استفاده کنید. برای مثال، میتوانید طرحبندیهای پیشفرض برنامه خود را در XML تعریف کنید و سپس طرحبندی را در زمان اجرا تغییر دهید.
XML را بنویسید
با استفاده از واژگان XML اندروید، میتوانید به سرعت طرحبندیهای رابط کاربری و عناصر صفحه نمایش موجود در آنها را طراحی کنید، همانطور که صفحات وب را در HTML با مجموعهای از عناصر تو در تو ایجاد میکنید.
هر فایل layout باید دقیقاً شامل یک عنصر ریشه باشد که باید یک شیء View یا ViewGroup باشد. پس از تعریف عنصر ریشه، میتوانید اشیاء layout یا ویجتهای اضافی را به عنوان عناصر فرزند اضافه کنید تا به تدریج یک سلسله مراتب View ایجاد شود که layout شما را تعریف میکند. برای مثال، در اینجا یک layout XML وجود دارد که از یک LinearLayout عمودی برای نگهداری یک TextView و یک Button استفاده میکند:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TextView android:id="@+id/text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello, I am a TextView" /> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello, I am a Button" /> </LinearLayout>
پس از اینکه طرحبندی خود را در XML تعریف کردید، فایل را با پسوند .xml در پوشه res/layout/ پروژه اندروید خود ذخیره کنید تا به درستی کامپایل شود.
برای اطلاعات بیشتر در مورد سینتکس یک فایل XML طرحبندی، به منبع طرحبندی مراجعه کنید.
بارگذاری منبع XML
وقتی برنامه خود را کامپایل میکنید، هر فایل طرحبندی XML به یک منبع View کامپایل میشود. منبع طرحبندی را در پیادهسازی فراخوانی Activity.onCreate() برنامه خود بارگذاری کنید. این کار را با فراخوانی setContentView() انجام دهید و مرجع منبع طرحبندی خود را به شکل زیر به آن منتقل کنید: R.layout. layout_file_name . برای مثال، اگر طرحبندی XML شما با نام main_layout.xml ذخیره شده است، آن را برای Activity خود به صورت زیر بارگذاری کنید:
کاتلین
fun onCreate(savedInstanceState: Bundle) { super.onCreate(savedInstanceState) setContentView(R.layout.main_layout) }
جاوا
public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main_layout); }
چارچوب اندروید، متد فراخوانی onCreate() را در Activity شما هنگام راهاندازی Activity فراخوانی میکند. برای اطلاعات بیشتر در مورد چرخه حیات activity، به بخش مقدمهای بر activities مراجعه کنید.
ویژگیها
هر شیء View و ViewGroup از انواع ویژگیهای XML خود پشتیبانی میکند. برخی از ویژگیها مختص یک شیء View هستند. به عنوان مثال، TextView از ویژگی textSize پشتیبانی میکند. با این حال، این ویژگیها توسط هر شیء View که از این کلاس ارثبری میکند نیز به ارث میرسند. برخی از آنها برای همه اشیاء View مشترک هستند، زیرا از کلاس View ریشه به ارث رسیدهاند، مانند ویژگی id . سایر ویژگیها به عنوان پارامترهای طرحبندی در نظر گرفته میشوند، که ویژگیهایی هستند که جهتگیریهای طرحبندی خاصی از شیء View را توصیف میکنند، همانطور که توسط شیء ViewGroup والد آن شیء تعریف شده است.
شناسه
هر شیء View میتواند یک شناسه عدد صحیح مرتبط با خود داشته باشد تا به طور منحصر به فرد View در درخت شناسایی کند. هنگامی که برنامه کامپایل میشود، این شناسه به عنوان یک عدد صحیح ارجاع داده میشود، اما شناسه معمولاً در فایل XML طرحبندی به عنوان یک رشته در ویژگی id اختصاص داده میشود. این یک ویژگی XML مشترک برای همه اشیاء View است و توسط کلاس View تعریف میشود. شما اغلب از آن استفاده میکنید. نحو شناسه درون یک تگ XML به شرح زیر است:
android:id="@+id/my_button"
علامت @ در ابتدای رشته نشان میدهد که تجزیهکننده XML بقیه رشته ID را تجزیه و بسط میدهد و آن را به عنوان یک منبع ID شناسایی میکند. علامت جمع (+) به این معنی است که این یک نام منبع جدید است که باید ایجاد شده و به منابع شما در فایل R.java اضافه شود.
چارچوب اندروید منابع شناسه (ID) بسیار دیگری را ارائه میدهد. هنگام ارجاع به شناسه منبع اندروید، نیازی به علامت جمع ندارید، اما باید فضای نام بسته android را به شرح زیر اضافه کنید:
android:id="@android:id/empty"
فضای نام پکیج android نشان میدهد که شما به جای کلاس منابع محلی، به یک شناسه از کلاس منابع android.R ارجاع میدهید.
برای ایجاد نماها و ارجاع آنها از برنامه خود، میتوانید از یک الگوی رایج به شرح زیر استفاده کنید:
- یک نما (view) در فایل طرحبندی (layout file) تعریف کنید و مانند مثال زیر، یک شناسه (id) منحصر به فرد به آن اختصاص دهید:
<Button android:id="@+id/my_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/my_button_text"/>
- یک نمونه از شیء view ایجاد کنید و آن را از layout دریافت کنید، معمولاً در متد
onCreate()، همانطور که در مثال زیر نشان داده شده است:کاتلین
val myButton: Button = findViewById(R.id.my_button)
جاوا
Button myButton = (Button) findViewById(R.id.my_button);
تعریف شناسه برای اشیاء نما هنگام ایجاد یک RelativeLayout مهم است. در یک طرحبندی نسبی، نماهای همنیا میتوانند طرحبندی خود را نسبت به نمای همنیای دیگری تعریف کنند که توسط شناسه منحصر به فرد ارجاع داده میشود.
یک شناسه (ID) لازم نیست در کل درخت منحصر به فرد باشد، اما باید در بخشی از درخت که جستجو میکنید منحصر به فرد باشد. اغلب ممکن است کل درخت باشد، بنابراین بهتر است در صورت امکان آن را منحصر به فرد کنید.
پارامترهای طرحبندی
ویژگیهای طرحبندی XML با نام layout_ something پارامترهای طرحبندی را برای View تعریف میکنند که برای ViewGroup که در آن قرار دارد مناسب هستند.
هر کلاس ViewGroup یک کلاس تو در تو را پیادهسازی میکند که ViewGroup.LayoutParams را بسط میدهد. این زیرکلاس شامل انواع ویژگیهایی است که اندازه و موقعیت هر نمای فرزند را متناسب با گروه نما تعریف میکنند. همانطور که در شکل 2 نشان داده شده است، گروه نمای والد، پارامترهای طرحبندی را برای هر نمای فرزند، از جمله گروه نمای فرزند، تعریف میکند.

هر زیرکلاس LayoutParams سینتکس مخصوص به خود را برای تنظیم مقادیر دارد. هر عنصر فرزند باید یک LayoutParams مناسب برای والد خود تعریف کند، اگرچه ممکن است برای فرزندان خود نیز LayoutParams متفاوتی تعریف کند.
همه گروههای نما شامل عرض و ارتفاع هستند که layout_width و layout_height استفاده میکنند و هر نما موظف است آنها را تعریف کند. بسیاری از LayoutParams شامل حاشیهها و مرزهای اختیاری هستند.
شما میتوانید عرض و ارتفاع را با اندازهگیریهای دقیق مشخص کنید، اما ممکن است نخواهید این کار را اغلب انجام دهید. اغلب، از یکی از این ثابتها برای تنظیم عرض یا ارتفاع استفاده میکنید:
-
wrap_content: به نمای شما میگوید که اندازه خود را به ابعاد مورد نیاز محتوایش برساند. -
match_parent: به نمای شما میگوید که تا جایی که گروه نمای والدش اجازه میدهد، بزرگ شود.
به طور کلی، توصیه نمیکنیم که عرض و ارتفاع طرحبندی را با استفاده از واحدهای مطلق مانند پیکسل مشخص کنید. رویکرد بهتر، استفاده از اندازهگیریهای نسبی مانند واحدهای پیکسل مستقل از چگالی (dp)، wrap_content یا match_parent است، زیرا به برنامه شما کمک میکند تا به درستی در اندازههای مختلف صفحه نمایش دستگاه نمایش داده شود. انواع اندازهگیریهای پذیرفته شده در Layout resource تعریف شدهاند.
موقعیت چیدمان
یک نما (view) هندسهای مستطیلی دارد. این نما دارای یک مکان است که به صورت جفت مختصات چپ و بالا بیان میشود و دو بُعد دارد که به صورت عرض و ارتفاع بیان میشوند. واحد مکان و ابعاد، پیکسل است.
شما میتوانید با فراخوانی متدهای getLeft() و getTop() موقعیت مکانی یک view را بازیابی کنید. متد اول مختصات چپ ( x ) مستطیلی که view را نشان میدهد را برمیگرداند. متد دوم مختصات بالای ( y ) مستطیلی که view را نشان میدهد را برمیگرداند. این متدها موقعیت مکانی view را نسبت به والدش برمیگردانند. برای مثال، وقتی getLeft() عدد 20 را برمیگرداند، به این معنی است که view در فاصله 20 پیکسل از سمت راست لبه چپ والد مستقیم خود قرار دارد.
علاوه بر این، روشهای راحتی برای جلوگیری از محاسبات غیرضروری وجود دارد: یعنی getRight() و getBottom() . این روشها مختصات لبههای راست و پایین مستطیلی که نمای را نشان میدهد، برمیگردانند. برای مثال، فراخوانی getRight() مشابه محاسبه زیر است: getLeft() + getWidth() .
اندازه، فاصلهگذاری و حاشیهها
اندازه یک نما با عرض و ارتفاع بیان میشود. یک نما دارای دو جفت مقدار عرض و ارتفاع است.
جفت اول به عنوان عرض اندازهگیری شده و ارتفاع اندازهگیری شده شناخته میشوند. این ابعاد مشخص میکنند که یک نما در داخل والد خود چقدر میخواهد بزرگ باشد. میتوانید ابعاد اندازهگیری شده را با فراخوانی getMeasuredWidth() و getMeasuredHeight() به دست آورید.
جفت دوم به عنوان عرض و ارتفاع یا گاهی اوقات عرض ترسیم و ارتفاع ترسیم شناخته میشود. این ابعاد، اندازه واقعی نمای روی صفحه، در زمان ترسیم و پس از طرحبندی را تعریف میکنند. این مقادیر ممکن است، اما لزوماً با عرض و ارتفاع اندازهگیری شده متفاوت نباشند. میتوانید عرض و ارتفاع را با فراخوانی getWidth() و getHeight() به دست آورید.
برای اندازهگیری ابعاد یک نما، فاصلهی بین عناصر (padding) آن در نظر گرفته میشود. فاصلهی بین عناصر برای قسمتهای چپ، بالا، راست و پایین نما بر حسب پیکسل بیان میشود. میتوانید از فاصلهی بین عناصر برای جابجایی محتوای نما به تعداد مشخصی پیکسل استفاده کنید. برای مثال، فاصلهی بین عناصر سمت چپ به اندازهی دو پیکسل، محتوای نما را دو پیکسل به سمت راست لبهی چپ منتقل میکند. میتوانید فاصلهی بین عناصر را با استفاده از متد setPadding(int, int, int, int) تنظیم کنید و با فراخوانی getPaddingLeft() ، getPaddingTop() ، getPaddingRight() و getPaddingBottom() از آن پرسوجو کنید.
اگرچه یک نما میتواند فاصلهگذاری (padding) تعریف کند، اما از حاشیهها پشتیبانی نمیکند. با این حال، گروههای نما از حاشیهها پشتیبانی میکنند. برای اطلاعات بیشتر به ViewGroup و ViewGroup.MarginLayoutParams مراجعه کنید.
برای اطلاعات بیشتر در مورد ابعاد، به بخش ابعاد مراجعه کنید.
علاوه بر تنظیم حاشیهها و فاصلهگذاری به صورت برنامهنویسی، میتوانید آنها را در طرحبندیهای XML خود نیز تنظیم کنید، همانطور که در مثال زیر نشان داده شده است:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TextView android:id="@+id/text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="16dp" android:padding="8dp" android:text="Hello, I am a TextView" /> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="16dp" android:paddingBottom="4dp" android:paddingEnd="8dp" android:paddingStart="8dp" android:paddingTop="4dp" android:text="Hello, I am a Button" /> </LinearLayout>
مثال قبلی نشان میدهد که حاشیه و فاصلهگذاری چگونه اعمال میشوند. TextView حاشیهها و فاصلهگذاری یکنواختی در همه جا دارد و Button نشان میدهد که چگونه میتوانید آنها را به طور مستقل در لبههای مختلف اعمال کنید.
طرحبندیهای رایج
هر زیرکلاس از کلاس ViewGroup روشی منحصر به فرد برای نمایش نماهایی که درون آن قرار میدهید، ارائه میدهد. انعطافپذیرترین نوع طرحبندی، و نوعی که بهترین ابزارها را برای کمعمق نگه داشتن سلسله مراتب طرحبندی شما فراهم میکند، ConstraintLayout است.
در ادامه برخی از انواع رایج طرحبندی که در پلتفرم اندروید تعبیه شدهاند، آورده شده است.

عناصر فرزند خود را در یک ردیف افقی یا عمودی سازماندهی میکند و اگر طول پنجره از طول صفحه نمایش بیشتر شود، یک نوار پیمایش ایجاد میکند.
ساخت لیستهای پویا
وقتی محتوای طرحبندی شما پویا است یا از پیش تعیین نشده است، میتوانید RecyclerView یا یک زیرکلاس از AdapterView استفاده کنید. RecyclerView عموماً گزینه بهتری است، زیرا از حافظه به طور کارآمدتری نسبت به AdapterView استفاده میکند.
طرحبندیهای رایجی که با RecyclerView و AdapterView امکانپذیر هستند شامل موارد زیر میشوند:
RecyclerView امکانات بیشتری ارائه میدهد و گزینهای برای ایجاد یک مدیر طرحبندی سفارشی است.
پر کردن نمای آداپتور با داده
شما میتوانید با اتصال نمونه AdapterView به یک Adapter ، یک AdapterView مانند ListView یا GridView را پر کنید، که دادهها را از یک منبع خارجی بازیابی میکند و یک View ایجاد میکند که هر ورودی داده را نشان میدهد.
اندروید چندین زیرکلاس از Adapter ارائه میدهد که برای بازیابی انواع مختلف دادهها و ساخت نماها برای AdapterView مفید هستند. دو مورد از رایجترین آداپتورها عبارتند از:
-
ArrayAdapter - وقتی منبع داده شما یک آرایه است از این آداپتور استفاده کنید. به طور پیشفرض،
ArrayAdapterبا فراخوانیtoString()روی هر آیتم آرایه و قرار دادن محتویات در یکTextView، برای هر آیتم آرایه یک نما ایجاد میکند.برای مثال، اگر آرایهای از رشتهها دارید که میخواهید در یک
ListViewنمایش دهید، با استفاده از یک سازنده، یکArrayAdapterجدید را مقداردهی اولیه کنید تا طرحبندی هر رشته و آرایه رشتهای را مشخص کنید:کاتلین
val adapter = ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, myStringArray)
جاوا
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, myStringArray);
آرگومانهای این سازنده به شرح زیر است:
-
Contextبرنامه شما - طرحبندی که شامل یک
TextViewبرای هر رشته در آرایه است - آرایه رشتهای
سپس تابع
setAdapter()درListViewخود فراخوانی کنید:کاتلین
val listView: ListView = findViewById(R.id.listview) listView.adapter = adapter
جاوا
ListView listView = (ListView) findViewById(R.id.listview); listView.setAdapter(adapter);
برای سفارشیسازی ظاهر هر آیتم، میتوانید متد
toString()را برای اشیاء موجود در آرایه خود بازنویسی کنید. یا برای ایجاد یک view برای هر آیتم که چیزی غیر ازTextViewباشد - برای مثال، اگر برای هر آیتم آرایه یکImageViewمیخواهید - کلاسArrayAdapterرا بسط دهید وgetView()را بازنویسی کنید تا نوع view مورد نظر شما برای هر آیتم را برگرداند. -
-
SimpleCursorAdapter - وقتی دادههای شما از یک
Cursorمیآیند، از این آداپتور استفاده کنید. هنگام استفاده ازSimpleCursorAdapter، یک طرحبندی برای استفاده برای هر ردیف درCursorو ستونهایی ازCursorکه میخواهید در نماهای طرحبندی مورد نظر وارد شوند، مشخص کنید. به عنوان مثال، اگر میخواهید لیستی از نام و شماره تلفن افراد ایجاد کنید، میتوانید یک پرسوجو انجام دهید که یکCursorحاوی یک ردیف برای هر فرد و ستونهایی برای نامها و شمارهها را برمیگرداند. سپس یک آرایه رشتهای ایجاد میکنید که مشخص میکند کدام ستونها ازCursorرا میخواهید در طرحبندی برای هر نتیجه و یک آرایه عدد صحیح که نماهای مربوطه را که هر ستون باید در آن قرار گیرد، مشخص میکند:کاتلین
val fromColumns = arrayOf(ContactsContract.Data.DISPLAY_NAME, ContactsContract.CommonDataKinds.Phone.NUMBER) val toViews = intArrayOf(R.id.display_name, R.id.phone_number)
جاوا
String[] fromColumns = {ContactsContract.Data.DISPLAY_NAME, ContactsContract.CommonDataKinds.Phone.NUMBER}; int[] toViews = {R.id.display_name, R.id.phone_number};
وقتی
SimpleCursorAdapterنمونهسازی میکنید، طرحبندی مورد استفاده برای هر نتیجه،Cursorحاوی نتایج و این دو آرایه را به آن ارسال کنید:کاتلین
val adapter = SimpleCursorAdapter(this, R.layout.person_name_and_number, cursor, fromColumns, toViews, 0) val listView = getListView() listView.adapter = adapter
جاوا
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, R.layout.person_name_and_number, cursor, fromColumns, toViews, 0); ListView listView = getListView(); listView.setAdapter(adapter);
سپس
SimpleCursorAdapterبا استفاده از طرحبندی ارائه شده، با قرار دادن هر آیتمfromColumnsدر نمایtoViewsمربوطه، برای هر ردیف درCursorیک نما ایجاد میکند.
اگر در طول عمر برنامهتان، دادههای زیربنایی که توسط آداپتور خوانده میشوند را تغییر دهید، تابع notifyDataSetChanged() را فراخوانی کنید. این تابع به view پیوست شده اطلاع میدهد که دادهها تغییر کردهاند و view خود را بهروزرسانی میکند.
مدیریت رویدادهای کلیک
شما میتوانید با پیادهسازی رابط AdapterView.OnItemClickListener به رویدادهای کلیک روی هر آیتم در AdapterView پاسخ دهید. برای مثال:
کاتلین
listView.onItemClickListener = AdapterView.OnItemClickListener { parent, view, position, id -> // Do something in response to the click. }
جاوا
// Create a message handling object as an anonymous class. private OnItemClickListener messageClickedHandler = new OnItemClickListener() { public void onItemClick(AdapterView parent, View v, int position, long id) { // Do something in response to the click. } }; listView.setOnItemClickListener(messageClickedHandler);
منابع اضافی
ببینید که چگونه از طرحبندیها در نسخه آزمایشی برنامه Sunflower در GitHub استفاده میشود.



