التنسيقات في طرق العرض

تجربة طريقة ComposeAllowed
Jetpack Compose هي مجموعة أدوات واجهة المستخدم التي ننصح بها لنظام التشغيل Android. تعرَّف على كيفية استخدام التنسيقات في Compose.

يحدِّد التنسيق بنية واجهة المستخدم في تطبيقك، كما هو الحال في نشاط. ويتم إنشاء جميع العناصر في التنسيق باستخدام تدرج هرمي لكائن View وViewGroup. ترسم View عادةً شيئًا يمكن للمستخدم رؤيته والتفاعل معه. ViewGroup هي حاوية غير مرئية تحدّد بنية التنسيق لـ View وكائنات ViewGroup الأخرى، كما هو موضّح في الشكل 1.

الشكل 1. صورة توضيحية لتدرّج هرمي لطريقة العرض يحدّد تنسيق واجهة المستخدم.

يُطلق غالبًا على كائنات View اسم التطبيقات المصغّرة، ويمكن أن تكون إحدى الفئات الفرعية العديدة، مثل Button أو TextView. يُطلق عادةً على كائنات ViewGroup اسم التنسيقات، وقد تكون نوعًا من الأنواع المتعددة التي توفّر بنية تنسيق مختلفة، مثل LinearLayout أو ConstraintLayout.

يمكنك الإعلان عن تنسيق بطريقتين:

  • توضيح عناصر واجهة المستخدم في ملف XML: يوفّر Android مفردات XML واضحة تتوافق مع فئات View وفئاتها الفرعية، مثل فئات التطبيقات المصغّرة والتنسيقات. يمكنك أيضًا استخدام محرِّر التنسيق في "استوديو Android" لإنشاء تنسيق XML باستخدام واجهة السحب والإفلات.

  • إنشاء مثيل لعناصر التنسيق في وقت التشغيل يمكن لتطبيقك إنشاء العنصرَين View وViewGroup ومعالجة خصائصهما آليًا.

يتيح لك تعريف واجهة المستخدم بتنسيق XML فصل طريقة عرض تطبيقك عن الرمز الذي يتحكم في سلوكه. يسهّل استخدام ملفات XML أيضًا توفير تخطيطات مختلفة لأحجام الشاشة والاتجاهات المختلفة. وقد تم تناول ذلك بالتفصيل في مقالة إتاحة أحجام الشاشة المختلفة.

يمنحك إطار عمل Android المرونة في استخدام إحدى هاتين الطريقتين أو كلتيهما لإنشاء واجهة المستخدم لتطبيقك. على سبيل المثال، يمكنك الإفصاح عن التنسيقات التلقائية لتطبيقك بتنسيق XML، ثم تعديل التنسيق في وقت التشغيل.

كتابة ملف XML

باستخدام مفردات XML الخاصة بنظام التشغيل Android، يمكنك تصميم تنسيقات واجهة المستخدم وعناصر الشاشة التي تحتوي عليها بسرعة، بالطريقة نفسها التي تنشئ بها صفحات ويب بتنسيق 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/ الخاص بمشروع Android حتى يتم تجميعه بشكل صحيح.

لمزيد من المعلومات عن بنية ملف XML للتنسيق، يُرجى الاطّلاع على مورد التنسيق.

تحميل مورد XML

عند تجميع تطبيقك، يتم تجميع كل ملف بتنسيق XML في مورد View. حمِّل مورد التنسيق في Activity.onCreate() تنفيذ معاودة الاتصال لتطبيقك. يمكنك إجراء ذلك من خلال طلب "setContentView()"، وإرساله المرجع إلى مورد التنسيق في النموذج: R.layout.layout_file_name. على سبيل المثال، إذا تم حفظ تنسيق XML بتنسيق main_layout.xml، يمكنك تحميله على Activity على النحو التالي:

Kotlin

fun onCreate(savedInstanceState: Bundle) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.main_layout)
}

Java

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main_layout);
}

يستدعي إطار عمل Android طريقة استدعاء onCreate() في Activity عند تشغيل Activity. لمزيد من المعلومات حول دورات حياة الأنشطة، راجع مقدمة في الأنشطة.

السمات

يتيح كل عنصر من كائنات 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"

يشير الرمز at (@) في بداية السلسلة إلى أنّ محلل XML يحلل بقية سلسلة المعرّف ويوسّعها ويحدّدها كمورد للمعرّف. يعني رمز الجمع (+) أن هذا اسم مورد جديد يجب إنشاؤه وإضافته إلى مواردك في ملف R.java.

يوفّر إطار عمل Android العديد من موارد المعرّفات الأخرى. عند الإشارة إلى معرّف مورد Android، لا تحتاج إلى رمز الجمع، ولكن عليك إضافة مساحة اسم الحزمة android على النحو التالي:

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

تشير مساحة اسم الحزمة android إلى أنّك تُشير إلى رقم تعريف من فئة موارد android.R، بدلاً من فئة الموارد المحلية.

لإنشاء طرق عرض والرجوع إليها من تطبيقك، يمكنك استخدام نمط شائع على النحو التالي:

  1. حدِّد ملفًا شخصيًا في ملف التنسيق وخصِّص له معرّفًا فريدًا، كما في المثال التالي:
    <Button android:id="@+id/my_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/my_button_text"/>
    
  2. أنشئ مثيلاً لعنصر العرض واحتفِظ به من التنسيق، عادةً باستخدام onCreate()، كما هو موضّح في المثال التالي:

    Kotlin

    val myButton: Button = findViewById(R.id.my_button)
    

    Java

    Button myButton = (Button) findViewById(R.id.my_button);
    

من المهم تحديد أرقام التعريف لعناصر الملف الشخصي عند إنشاء RelativeLayout. في التنسيق النسبي، يمكن أن تحدد طرق العرض التابعة تنسيقها بالنسبة إلى طريقة العرض التابعة الأخرى، والتي تتم الإشارة إليها بواسطة المعرف الفريد.

لا يلزم أن يكون المعرف فريدًا عبر الشجرة بالكامل، ولكن يجب أن يكون فريدًا داخل الجزء الذي تبحث عنه في الشجرة. قد تكون غالبًا الشجرة بأكملها، لذلك من الأفضل أن تجعلها فريدة عندما يكون ذلك ممكنًا.

معلمات التنسيق

تحدّد سمات تنسيق XML المسماة layout_something معلَمات تنسيق للسمة View المناسبة للسمة ViewGroup المتوفّرة فيها.

تنفِّذ كل فئة ViewGroup فئة مدمَجة تمتد إلى ViewGroup.LayoutParams. وتضم هذه الفئة الفرعية أنواع الخصائص التي تحدد حجم وموضع كل ملف شخصي فرعي، حسبما يتناسب مع مجموعة الملفات الشخصية. وكما هو موضّح في الشكل 2، تحدِّد مجموعة طرق العرض الرئيسية معلَمات التنسيق لكل طريقة عرض فرعية، بما في ذلك مجموعة طرق العرض الفرعية.

الشكل 2. التمثيل البصري للتدرّج الهرمي للمشاهدات مع مَعلمات التنسيق المرتبطة بكل ملف شخصي

لكل فئة فرعية في LayoutParams بنية خاصة بها لضبط القيم. ويجب أن يحدّد كل عنصر فرعي قيمة LayoutParams مناسبة للعنصر الرئيسي، ولكن قد تحدّد أيضًا قيمة LayoutParams مختلفة لعناصره الثانوية.

تشمل جميع مجموعات طرق العرض عرضًا وارتفاعًا، باستخدام layout_width وlayout_height، ويجب تحديدهما في كل طريقة عرض. يتضمن العديد من LayoutParams هوامش وحدود اختيارية.

يمكنك تحديد العرض والارتفاع باستخدام القياسات الدقيقة، ولكنك قد لا ترغب في إجراء ذلك كثيرًا. في كثير من الأحيان، يمكنك استخدام أحد هذه الثوابت لتعيين العرض أو الارتفاع:

  • wrap_content: يقيّم هذا السمة طريقة العرض بما يتناسب مع الحجم نفسه للأبعاد التي يتطلبها المحتوى.
  • match_parent: يعبّر هذا المقياس عن حجم المشاهدة بقدر ما تسمح به مجموعة المشاهدات الرئيسية.

وبشكل عام، لا ننصح بتحديد عرض التنسيق وارتفاعه باستخدام الوحدات المطلقة مثل وحدات البكسل. هناك نهج أفضل وهو استخدام القياسات النسبية، مثل وحدات البكسل المستقلة الكثافة (dp) أو wrap_content أو match_parent، لأنّها تساعد تطبيقك على العرض بشكل سليم على مستوى مجموعة متنوعة من أحجام شاشات الأجهزة. يتم تحديد أنواع القياس المقبولة في مورد التنسيق.

موضع التصميم

طريقة العرض بأشكال هندسية مستطيلة. ويكون له موقع، ويتم التعبير عنه كزوج من الإحداثيات لليسار والأعلى وأبعاده، ويتم التعبير عنها بالعرض والارتفاع. وحدة الموقع والأبعاد هي البكسل.

يمكنك استرداد موقع العرض من خلال استدعاء الطريقتين getLeft() و getTop(). تعرض القيمة الأولى الإحداثي الأيسر (x) للمستطيل الذي يمثّل طريقة العرض. ويعرض الإصدار الأخير الإحداثي العلوي (y) للمستطيل الذي يمثّل طريقة العرض. تعرض هذه الطرق موقع العرض نسبةً إلى الأصل. على سبيل المثال، عندما تعرض الدالة getLeft() القيمة 20، هذا يعني أنّ طريقة العرض تقع على بُعد 20 بكسل على يمين الحافة اليسرى للشاشة الرئيسية المباشرة.

بالإضافة إلى ذلك، هناك طرق ملائمة لتجنُّب العمليات الحسابية غير الضرورية، وهي: getRight() وgetBottom(). تعرض هذه الطرق إحداثيات الحافتين اليمنى والسفلية للمستطيل التي تمثل العرض. على سبيل المثال، يشبه استدعاء getRight() عملية المعالجة التالية: getLeft() + getWidth().

الحجم والمساحة المتروكة والهوامش

يتم التعبير عن حجم طريقة العرض من خلال العرض والارتفاع. تحتوي طريقة العرض على زوجين من قيم العرض والارتفاع.

يُعرف الزوج الأول باسم العرض الذي تم قياسه والارتفاع الذي تم قياسه. وتحدد هذه الأبعاد مدى تكبير العرض ضمن الأصل. يمكنك الحصول على السمات التي تم قياسها من خلال استدعاء getMeasuredWidth() وgetMeasuredHeight().

يُعرف الزوج الثاني باسم width وheight أو أحيانًا رسم العرض ورسم الارتفاع. تحدد هذه الأبعاد الحجم الفعلي للعرض على الشاشة، في وقت الرسم وبعد التخطيط. قد تختلف هذه القيم، ولكن لا ينبغي ذلك، عن العرض والارتفاع الذين تم قياسهم. ويمكنك الحصول على العرض والارتفاع عن طريق استدعاء getWidth() وgetHeight().

لقياس أبعاده، تأخذ طريقة العرض في الاعتبار المساحة المتروكة الخاصة بها. يتم التعبير عن المساحة المتروكة بالبكسل للأجزاء اليسرى والعلوية واليمنى والسفلية من العرض. يمكنك استخدام المساحة المتروكة لمعادلة محتوى العرض بعدد معيّن من وحدات البكسل. على سبيل المثال، تؤدي المساحة المتروكة اليسرى المكونة من اثنتين إلى دفع محتوى العرض ببكسلتين إلى يمين الحافة اليسرى. يمكنك ضبط المساحة المتروكة باستخدام الطريقة setPadding(int, int, int, int) وإجراء طلب بحث عنها من خلال استدعاء getPaddingLeft() وgetPaddingTop() وgetPaddingRight() وgetPaddingBottom().

على الرغم من أن طريقة العرض يمكنها تحديد مساحة متروكة، إلا أنها لا تدعم الهوامش. ومع ذلك، تدعم مجموعات العرض الهوامش. يمكنك الاطّلاع على 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" الذي يوفّر أفضل الأدوات للحفاظ على سطحية التدرّج الهرمي للتصميم.

فيما يلي بعض أنواع التخطيط الشائعة المضمنة في نظام Android الأساسي.

إنشاء تنسيق خطي

تنظّم العناصر الثانوية في صف أفقي أو عمودي واحد وتنشئ شريط تمرير إذا تجاوز طول النافذة طول الشاشة.

إنشاء تطبيقات ويب في WebView

عرض صفحات الويب

إنشاء قوائم ديناميكية

عندما يكون محتوى التنسيق ديناميكيًا أو غير محدَّد مسبقًا، يمكنك استخدام RecyclerView أو فئة فرعية من AdapterView. بشكل عام، يكون RecyclerView الخيار الأفضل لأنّه يستخدم الذاكرة بكفاءة أكبر من AdapterView.

تتضمّن التنسيقات الشائعة التي يمكن استخدامها مع RecyclerView وAdapterView ما يلي:

القائمة

عرض قائمة عمود واحد قابل للتمرير.

الشبكة

تعرض شبكة تمرير من الأعمدة والصفوف.

يوفر RecyclerView المزيد من الاحتمالات وخيار إنشاء مدير تخطيط مخصص.

ملء عرض المحوّل بالبيانات

يمكنك تعبئة AdapterView مثل ListView أو GridView من خلال ربط مثيل AdapterView بـ Adapter، الذي يسترجع البيانات من مصدر خارجي وينشئ View يمثّل كل إدخال بيانات.

يوفّر Android عدة فئات فرعية من Adapter مفيدة لاسترداد أنواع البيانات المختلفة وإنشاء طرق عرض لـ AdapterView. المحولان الأكثر شيوعًا هما:

ArrayAdapter
استخدِم هذا المحوّل عندما يكون مصدر البيانات مصفوفة. ينشئ ArrayAdapter تلقائيًا طريقة عرض لكل عنصر مصفوفة من خلال استدعاء toString() في كل عنصر ووضع المحتوى في TextView.

على سبيل المثال، إذا كان لديك مصفوفة من السلاسل تريد عرضها في ListView، عليك إعداد ArrayAdapter جديدة باستخدام دالة إنشاء لتحديد تنسيق كل سلسلة ومصفوفة السلسلة:

Kotlin

    val adapter = ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, myStringArray)
    

Java

    ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
            android.R.layout.simple_list_item_1, myStringArray);
    

في ما يلي وسيطات الدالة الإنشائية هذه:

  • تطبيقك Context
  • التنسيق الذي يحتوي على TextView لكل سلسلة في المصفوفة
  • صفيف السلسلة

بعد ذلك، يمكنك الاتصال برقم setAdapter() على ListView:

Kotlin

    val listView: ListView = findViewById(R.id.listview)
    listView.adapter = adapter
    

Java

    ListView listView = (ListView) findViewById(R.id.listview);
    listView.setAdapter(adapter);
    

لتخصيص مظهر كل عنصر، يمكنك إلغاء الطريقة toString() للكائنات في المصفوفة. ولإنشاء طريقة عرض لكل عنصر بخلاف السمة TextView، على سبيل المثال، إذا أردت عرض السمة ImageView لكل عنصر في مصفوفة، يمكنك تمديد الفئة ArrayAdapter وإلغاء getView() لعرض نوع العرض الذي تريده لكل عنصر.

SimpleCursorAdapter
استخدِم هذا المحوّل عندما تأتي بياناتك من Cursor. عند استخدام SimpleCursorAdapter، حدِّد تنسيقًا لاستخدامه مع كل صف في Cursor والأعمدة في Cursor التي تريد إدراجها في طرق عرض التنسيق المطلوب. على سبيل المثال، إذا أردت إنشاء قائمة بأسماء الأشخاص وأرقام هواتفهم، يمكنك تنفيذ طلب بحث يعرض Cursor يحتوي على صف لكل شخص وأعمدة للأسماء والأرقام. ويمكنك بعد ذلك إنشاء مصفوفة سلسلة وتحدّد الأعمدة من Cursor التي تريدها في التنسيق لكل نتيجة ومصفوفة عدد صحيح تحدِّد طرق العرض المقابلة التي يجب وضع كل عمود فيها:

Kotlin

    val fromColumns = arrayOf(ContactsContract.Data.DISPLAY_NAME,
                              ContactsContract.CommonDataKinds.Phone.NUMBER)
    val toViews = intArrayOf(R.id.display_name, R.id.phone_number)
    

Java

    String[] fromColumns = {ContactsContract.Data.DISPLAY_NAME,
                            ContactsContract.CommonDataKinds.Phone.NUMBER};
    int[] toViews = {R.id.display_name, R.id.phone_number};
    

عند إنشاء مثيل لـ SimpleCursorAdapter، عليك ضبط التنسيق لاستخدامه مع كل نتيجة وCursor الذي يحتوي على النتائج وهاتَين الصفيفتَين:

Kotlin

    val adapter = SimpleCursorAdapter(this,
            R.layout.person_name_and_number, cursor, fromColumns, toViews, 0)
    val listView = getListView()
    listView.adapter = adapter
    

Java

    SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,
            R.layout.person_name_and_number, cursor, fromColumns, toViews, 0);
    ListView listView = getListView();
    listView.setAdapter(adapter);
    

تنشئ SimpleCursorAdapter بعد ذلك طريقة عرض لكل صف في Cursor باستخدام التنسيق المتوفر من خلال إدراج كل عنصر fromColumns في طريقة عرض toViews المقابلة.

إذا غيّرت البيانات الأساسية التي يقرأها المحوّل على مدار عمر التطبيق، اتصل بالرقم notifyDataSetChanged(). يؤدي ذلك إلى إعلام العرض المرفق بأن البيانات قد تم تغييرها وتتم إعادة تحميلها.

التعامل مع الأحداث الناتجة عن النقر

يمكنك الاستجابة لأحداث النقر على كل عنصر في AdapterView من خلال تنفيذ واجهة AdapterView.OnItemClickListener. على سبيل المثال:

Kotlin

listView.onItemClickListener = AdapterView.OnItemClickListener { parent, view, position, id ->
    // Do something in response to the click.
}

Java

// 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.