چیدمان ها در نماها
یک طرح، ساختار یک رابط کاربری را در برنامه شما، مانند یک فعالیت ، تعریف می کند. همه عناصر در طرح با استفاده از سلسله مراتبی از اشیاء View
و ViewGroup
ساخته می شوند. یک View
معمولاً چیزی را ترسیم می کند که کاربر می تواند ببیند و با آن تعامل داشته باشد. ViewGroup
یک محفظه نامرئی است که ساختار طرح بندی View
و سایر اشیاء ViewGroup
را همانطور که در شکل 1 نشان داده شده است، تعریف می کند.
اشیاء View
اغلب ویجت نامیده می شوند و می توانند یکی از بسیاری از زیر کلاس ها مانند Button
یا TextView
باشند. اشیاء ViewGroup
معمولاً Layout نامیده می شوند و می توانند یکی از انواع مختلفی باشند که ساختار طرح بندی متفاوتی را ارائه می دهند، مانند LinearLayout
یا ConstraintLayout
.
شما می توانید یک طرح را به دو روش اعلام کنید:
- عناصر UI را در XML اعلام کنید. Android یک واژگان ساده XML ارائه میکند که با کلاسها و زیر کلاسهای
View
مطابقت دارد، مانند آنهایی که برای ویجتها و طرحبندیها هستند. همچنین میتوانید از ویرایشگر طرحبندی اندروید استودیو برای ایجاد طرحبندی XML خود با استفاده از رابط کشیدن و رها کردن استفاده کنید. - المانهای چیدمان را در زمان اجرا مشخص کنید. برنامه شما می تواند اشیاء
View
وViewGroup
را ایجاد کند و ویژگی های آنها را به صورت برنامه ریزی شده دستکاری کند.
اعلان رابط کاربری خود در XML به شما امکان می دهد ارائه برنامه خود را از کدی که رفتار آن را کنترل می کند جدا کنید. استفاده از فایلهای XML نیز ارائه طرحبندیهای مختلف برای اندازهها و جهتهای مختلف صفحه را آسانتر میکند. این مورد بیشتر در پشتیبانی از اندازه های مختلف صفحه نمایش مورد بحث قرار گرفته است.
فریم ورک اندروید به شما این امکان را می دهد که از یکی یا هر دوی این روش ها برای ایجاد رابط کاربری برنامه خود استفاده کنید. برای مثال، میتوانید طرحبندیهای پیشفرض برنامهتان را در XML اعلام کنید، و سپس در زمان اجرا، طرحبندی را تغییر دهید.
XML را بنویسید
با استفاده از واژگان XML اندروید، میتوانید بهسرعت طرحبندیهای رابط کاربری و عناصر صفحهنمایش حاوی آنها را طراحی کنید، به همان روشی که صفحات وب را در HTML با یک سری عناصر تودرتو ایجاد میکنید.
هر فایل طرح بندی باید دقیقاً حاوی یک عنصر ریشه باشد که باید یک شی View
یا ViewGroup
باشد. پس از تعریف عنصر ریشه، می توانید اشیاء یا ویجت های طرح بندی اضافی را به عنوان عناصر فرزند اضافه کنید تا به تدریج یک سلسله مراتب View
ایجاد کنید که چیدمان شما را تعریف می کند. به عنوان مثال، در اینجا یک طرح 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 طرحبندی، به منبع Layout مراجعه کنید.
منبع 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); }
هنگامی که Activity
راه اندازی می شود، فریم ورک اندروید متد onCreate()
را در Activity
شما فراخوانی می کند. برای اطلاعات بیشتر در مورد چرخه عمر فعالیت، به مقدمه فعالیت ها مراجعه کنید.
صفات
هر شی View
و ViewGroup
از انواع ویژگی های XML خود پشتیبانی می کند. برخی از ویژگی ها مختص یک شی View
هستند. به عنوان مثال، TextView
از ویژگی textSize
پشتیبانی می کند. با این حال، این ویژگی ها توسط هر شی View
که این کلاس را گسترش می دهد نیز به ارث می رسد. برخی از آنها برای همه اشیاء View
مشترک هستند، زیرا مانند ویژگی id
از کلاس View
root به ارث برده می شوند. سایر ویژگیها پارامترهای طرحبندی در نظر گرفته میشوند، که ویژگیهایی هستند که جهتگیریهای طرحبندی خاصی از شی View
را که توسط شی ViewGroup
والد آن شی تعریف میشود، توصیف میکنند.
شناسه
هر شی View
می تواند یک شناسه عدد صحیح مرتبط با آن داشته باشد تا View
درون درخت را به طور منحصر به فرد شناسایی کند. هنگامی که برنامه کامپایل می شود، این شناسه به عنوان یک عدد صحیح ارجاع می شود، اما شناسه معمولاً در فایل XML طرح بندی به عنوان رشته ای در ویژگی id
اختصاص داده می شود. این یک ویژگی XML مشترک برای تمام اشیاء View
است و توسط کلاس View
تعریف می شود. شما اغلب از آن استفاده می کنید. سینتکس یک ID درون تگ XML به شرح زیر است:
android:id="@+id/my_button"
نماد at (@) در ابتدای رشته نشان می دهد که تجزیه کننده XML بقیه رشته ID را تجزیه و گسترش می دهد و آن را به عنوان یک منبع ID شناسایی می کند. علامت مثبت (+) به این معنی است که این یک نام منبع جدید است که باید ایجاد شود و به منابع شما در فایل R.java
اضافه شود.
چارچوب Android بسیاری از منابع ID دیگر را ارائه می دهد. هنگام ارجاع به شناسه منبع Android، به علامت مثبت نیاز ندارید، اما باید فضای نام بسته android
را به صورت زیر اضافه کنید:
android:id="@android:id/empty"
فضای نام بسته android
نشان می دهد که شما به جای کلاس منابع محلی، به یک شناسه از کلاس منابع android.R
ارجاع می دهید.
برای ایجاد نماها و ارجاع به آنها از برنامه خود، می توانید از یک الگوی رایج به شرح زیر استفاده کنید:
- یک View را در فایل layout تعریف کنید و به آن یک شناسه منحصربفرد اختصاص دهید، مانند مثال زیر:
<Button android:id="@+id/my_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/my_button_text"/>
- یک نمونه از شی view ایجاد کنید و آن را از طرح، معمولاً در متد
onCreate()
بگیرید، همانطور که در مثال زیر نشان داده شده است:کاتلین
val myButton: Button = findViewById(R.id.my_button)
جاوا
Button myButton = (Button) findViewById(R.id.my_button);
هنگام ایجاد یک RelativeLayout
، تعریف شناسه برای اشیاء مشاهده مهم است. در طرحبندی نسبی، نماهای خواهر و برادر میتوانند طرحبندی خود را نسبت به نمای خواهر یا برادر دیگری که با شناسه منحصربهفرد ارجاع داده میشود، تعریف کنند.
نیازی نیست که یک شناسه در کل درخت منحصر به فرد باشد، اما باید در بخشی از درختی که جستجو می کنید منحصر به فرد باشد. اغلب ممکن است کل درخت باشد، بنابراین بهتر است در صورت امکان آن را منحصر به فرد کنید.
پارامترهای چیدمان
ویژگی های طرح بندی XML به نام layout_ something
پارامترهای طرح بندی را برای View
تعریف می کند که برای ViewGroup
که در آن قرار دارد مناسب است.
هر کلاس ViewGroup
یک کلاس تودرتو پیاده سازی می کند که ViewGroup.LayoutParams
را گسترش می دهد. این زیر کلاس حاوی انواع ویژگی است که اندازه و موقعیت هر نمای فرزند را متناسب با گروه view تعریف می کند. همانطور که در شکل 2 نشان داده شده است، گروه نمای والدین، پارامترهای طرح بندی را برای هر نمای فرزند، از جمله گروه نمای فرزند، تعریف می کند.
هر زیر کلاس LayoutParams
سینتکس مخصوص به خود را برای تنظیم مقادیر دارد. هر عنصر فرزند باید یک LayoutParams
مناسب برای والد خود تعریف کند، اگرچه ممکن است LayoutParams
متفاوتی را برای فرزندان خود نیز تعریف کند.
همه گروههای نمایش شامل عرض و ارتفاع هستند که از layout_width
و layout_height
استفاده میکنند و هر نما برای تعریف آنها لازم است. بسیاری از LayoutParams
دارای حاشیه ها و حاشیه های اختیاری هستند.
شما می توانید عرض و ارتفاع را با اندازه گیری های دقیق مشخص کنید، اما ممکن است نخواهید این کار را اغلب انجام دهید. بیشتر اوقات، شما از یکی از این ثابت ها برای تنظیم عرض یا ارتفاع استفاده می کنید:
-
wrap_content
: به نمای شما میگوید که اندازههای خود را به اندازههای مورد نیاز محتوای آن اندازه بگیرد. -
match_parent
: به نمای شما می گوید که به اندازه ای که گروه نمای والد آن اجازه می دهد بزرگ شود.
به طور کلی، تعیین عرض و ارتفاع طرح با استفاده از واحدهای مطلق مانند پیکسل را توصیه نمی کنیم. یک رویکرد بهتر استفاده از اندازهگیریهای نسبی مانند واحدهای پیکسل مستقل از چگالی (dp)، wrap_content
یا match_parent
است، زیرا به برنامه شما کمک میکند تا در اندازههای مختلف صفحه نمایش دستگاه به درستی نمایش داده شود. انواع اندازه گیری پذیرفته شده در منبع Layout تعریف شده است.
موقعیت چیدمان
یک نمای دارای هندسه مستطیلی است. دارای یک مکان است که به صورت یک جفت مختصات سمت چپ و بالا و دو بعد به صورت عرض و ارتفاع بیان می شود. واحد مکان و ابعاد پیکسل است.
شما می توانید مکان یک view را با فراخوانی متدهای getLeft()
و getTop()
بازیابی کنید. اولی مختصات سمت چپ ( x ) مستطیل را که نمایانگر نمای است برمی گرداند. دومی مختصات بالای ( y ) مستطیل را که نمایانگر نمای است برمی گرداند. این روشها مکان نما را نسبت به والد آن برمیگردانند. به عنوان مثال، وقتی getLeft()
20 را برمی گرداند، به این معنی است که نمای 20 پیکسل در سمت راست لبه سمت چپ والد مستقیم خود قرار دارد.
علاوه بر این، روشهای راحتی برای جلوگیری از محاسبات غیر ضروری وجود دارد: یعنی getRight()
و getBottom()
. این روش ها مختصات لبه های سمت راست و پایین مستطیل را که نمایانگر نما است، برمی گرداند. برای مثال، فراخوانی getRight()
مشابه محاسبه زیر است: getLeft() + getWidth()
.
اندازه، بالشتک، و حاشیه
اندازه یک نما با عرض و ارتفاع بیان می شود. یک نما دارای دو جفت مقدار عرض و ارتفاع است.
جفت اول به عنوان عرض اندازه گیری شده و ارتفاع اندازه گیری شده شناخته می شود. این ابعاد مشخص میکنند که یک دیدگاه چقدر میخواهد در والد خود باشد. می توانید ابعاد اندازه گیری شده را با فراخوانی getMeasuredWidth()
و getMeasuredHeight()
بدست آورید.
جفت دوم به عرض و ارتفاع و یا گاهی عرض و ارتفاع رسم معروف است . این ابعاد، اندازه واقعی نمای روی صفحه، در زمان ترسیم و بعد از چیدمان را تعیین می کنند. این مقادیر ممکن است، اما لازم نیست، با عرض و ارتفاع اندازه گیری شده متفاوت باشد. می توانید عرض و ارتفاع را با فراخوانی getWidth()
و getHeight()
بدست آورید.
برای اندازه گیری ابعاد آن، یک نما، بالشتک آن را در نظر می گیرد. بالشتک برای قسمت های چپ، بالا، راست و پایین نمای به صورت پیکسل بیان می شود. می توانید از padding برای جبران محتوای نما با تعداد مشخصی پیکسل استفاده کنید. برای مثال، یک بالشتک دوتایی سمت چپ، محتوای نما را دو پیکسل به سمت راست لبه سمت چپ فشار میدهد. می توانید با استفاده از متد setPadding(int, int, int, int)
padding را تنظیم کنید و با فراخوانی getPaddingLeft()
, getPaddingTop()
, getPaddingRight()
و getPaddingBottom()
آن را پرس و جو کنید.
اگرچه یک نما می تواند یک بالشتک را تعریف کند، اما از حاشیه ها پشتیبانی نمی کند. با این حال، گروههای نمایش از حاشیهها پشتیبانی میکنند. برای اطلاعات بیشتر به ViewGroup
و ViewGroup.MarginLayoutParams
مراجعه کنید.
برای اطلاعات بیشتر در مورد ابعاد، به ابعاد مراجعه کنید.
همانطور که در مثال زیر نشان داده شده است، علاوه بر تنظیم حاشیه ها و padding به صورت برنامه ای، می توانید آنها را در طرح بندی های 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>
مثال قبلی نشان می دهد که حاشیه و padding اعمال شده است. TextView
دارای حاشیه های یکنواخت و بالشتک هایی است که در اطراف اعمال می شود، و Button
نشان می دهد که چگونه می توانید آنها را به طور مستقل در لبه های مختلف اعمال کنید.
چیدمان های رایج
هر زیر کلاس از کلاس ViewGroup
یک راه منحصر به فرد برای نمایش نماهایی که درون آن قرار می دهید ارائه می دهد. منعطف ترین نوع چیدمان، و بهترین ابزار برای کم عمق نگه داشتن سلسله مراتب طرح بندی شما، ConstraintLayout
است.
در زیر برخی از انواع چیدمان متداول ساخته شده در پلتفرم اندروید آورده شده است.
فرزندان خود را در یک ردیف افقی یا عمودی سازماندهی می کند و در صورتی که طول پنجره از طول صفحه بیشتر شود، یک نوار پیمایش ایجاد می کند.
لیست های پویا بسازید
وقتی محتوای طرحبندی شما پویا است یا از پیش تعیین نشده است، میتوانید از RecyclerView
یا زیر کلاس AdapterView
استفاده کنید. RecyclerView
به طور کلی گزینه بهتری است، زیرا از حافظه کارآمدتر از AdapterView
استفاده می کند.
طرحبندیهای رایج ممکن با RecyclerView
و AdapterView
شامل موارد زیر است:
RecyclerView
امکانات بیشتر و گزینه ای برای ایجاد یک مدیر طرح بندی سفارشی ارائه می دهد.
نمای آداپتور را با داده پر کنید
میتوانید یک AdapterView
مانند ListView
یا GridView
را با اتصال نمونه AdapterView
به یک Adapter
پر کنید، که دادهها را از یک منبع خارجی بازیابی میکند و یک View
ایجاد میکند که هر ورودی داده را نشان میدهد.
Android چندین زیر کلاس از 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()
برای اشیاء موجود در آرایه خود لغو کنید. یا، برای ایجاد یک نمای برای هر آیتم که چیزی غیر ازTextView
است - برای مثال، اگر برای هر آیتم آرایه یکImageView
میخواهید، کلاسArrayAdapter
را گسترش دهید وgetView()
را لغو کنید تا نوع نمای مورد نظر برای هر آیتم را برگردانید. -
-
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()
تماس بگیرید. این به نمای پیوست اطلاع می دهد که داده ها تغییر کرده اند و خود به روز می شود.
رویدادهای کلیک را مدیریت کنید
می توانید با اجرای رابط 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 را ببینید.