چیدمان ها در نماها

روش Compose را امتحان کنید
Jetpack Compose جعبه ابزار UI توصیه شده برای اندروید است. نحوه کار با طرح‌بندی‌ها در Compose را بیاموزید.

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

شکل 1. تصویر یک سلسله مراتب نمای، که یک طرح UI را تعریف می کند.

اشیاء 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 تعریف می شود. شما اغلب از آن استفاده می کنید. سینتکس یک شناسه داخل تگ XML به صورت زیر است:

android:id="@+id/my_button"

نماد at (@) در ابتدای رشته نشان می دهد که تجزیه کننده XML بقیه رشته ID را تجزیه و گسترش می دهد و آن را به عنوان یک منبع ID شناسایی می کند. علامت مثبت (+) به این معنی است که این یک نام منبع جدید است که باید ایجاد شود و به منابع شما در فایل R.java اضافه شود.

چارچوب Android بسیاری از منابع ID دیگر را ارائه می دهد. هنگام ارجاع به شناسه منبع Android، به علامت مثبت نیاز ندارید، اما باید فضای نام بسته android را به صورت زیر اضافه کنید:

android:id="@android:id/empty"

فضای نام بسته android نشان می دهد که شما به جای کلاس منابع محلی، به یک شناسه از کلاس منابع android.R ارجاع می دهید.

برای ایجاد نماها و ارجاع به آنها از برنامه خود، می توانید از یک الگوی رایج به شرح زیر استفاده کنید:

  1. یک View را در فایل layout تعریف کنید و به آن یک شناسه منحصربفرد اختصاص دهید، مانند مثال زیر:
    <Button android:id="@+id/my_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/my_button_text"/>
    
  2. یک نمونه از شی 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 نشان داده شده است، گروه نمای والدین، پارامترهای طرح بندی را برای هر نمای فرزند، از جمله گروه نمای فرزند، تعریف می کند.

شکل 2. تجسم سلسله مراتب نما با پارامترهای چیدمان مرتبط با هر نما.

هر زیر کلاس LayoutParams سینتکس مخصوص به خود را برای تنظیم مقادیر دارد. هر عنصر فرزند باید یک LayoutParams مناسب برای والد خود تعریف کند، اگرچه ممکن است LayoutParams متفاوتی را برای فرزندان خود نیز تعریف کند.

همه گروه‌های نمایش شامل عرض و ارتفاع هستند که از layout_width و layout_height استفاده می‌کنند و هر نما برای تعریف آنها لازم است. بسیاری از LayoutParams دارای حاشیه ها و حاشیه های اختیاری هستند.

شما می توانید عرض و ارتفاع را با اندازه گیری های دقیق مشخص کنید، اما ممکن است نخواهید این کار را اغلب انجام دهید. اغلب، شما از یکی از این ثابت ها برای تنظیم عرض یا ارتفاع استفاده می کنید:

  • wrap_content : به نمای شما می‌گوید که اندازه‌های خود را به اندازه‌های مورد نیاز محتوای آن اندازه بگیرد.
  • match_parent : به نمای شما می گوید که به اندازه ای که گروه نمای والد آن اجازه می دهد بزرگ شود.

به طور کلی، تعیین عرض و ارتفاع طرح با استفاده از واحدهای مطلق مانند پیکسل را توصیه نمی کنیم. یک رویکرد بهتر استفاده از اندازه‌گیری‌های نسبی مانند واحدهای پیکسل مستقل از چگالی (dp)، wrap_content یا match_parent است، زیرا به برنامه شما کمک می‌کند تا در اندازه‌های مختلف صفحه نمایش دستگاه به درستی نمایش داده شود. انواع اندازه گیری پذیرفته شده در منبع Layout تعریف شده است.

موقعیت چیدمان

یک نمای دارای هندسه مستطیلی است. دارای یک مکان است که به صورت یک جفت مختصات سمت چپ و بالا و دو بعد به صورت عرض و ارتفاع بیان می شود. واحد مکان و ابعاد پیکسل است.

با استفاده از متدهای getLeft() و getTop() می توانید مکان یک view را بازیابی کنید. اولی مختصات چپ ( 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 است.

در زیر برخی از انواع چیدمان متداول ساخته شده در پلتفرم اندروید آورده شده است.

یک طرح خطی ایجاد کنید

فرزندان خود را در یک ردیف افقی یا عمودی سازماندهی می کند و در صورتی که طول پنجره از طول صفحه بیشتر شود، یک نوار پیمایش ایجاد می کند.

ساخت برنامه های وب در WebView

صفحات وب را نمایش می دهد.

لیست های پویا بسازید

وقتی محتوای طرح‌بندی شما پویا است یا از پیش تعیین نشده است، می‌توانید از 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 را ببینید.