سلسلة تعلم الأندرويد – الحلقة التاسعة: الواجهة الرسومية القائمة

السلام عليكم

في الحلقة السابقة قمت بشرح الواجهات الرسومية الأساسية في الأندرويد أو الأطر الرسومية وفي هذه الحلقة سوف أقوم بشرح واجهة القائمة ListView وكيفية استعمالها. والسبب الذي جعلني أفرد حلقة خاصة لهذه الواجهة هو كثرة تطبيقاتها واستعمالتها في مختلف تطبيقات الأندرويد. تستعمل هذه الواجهة عادة عند عرض مجموعة معلومات قصيرة وكثيرة العدد مثل جهات الاتصال، الرسال النصية وغيرها. وقد استعملت هذه الواجهة في تطبيق iAndroidQuran لعرض أسماء السور والآيات أيضاً. يمكن تزويد القائمة بالمعلومات من خلال محوّل Adapter يستعمل مصفوفة أو قواعد البيانات، ويوجد في الأندرويد العديد من كلاسات المحوّلات Adapter التي تقوم بربط الواجهة بالمعلومات. هناك عادة طريقتان لاستعمال هذه الكلاسات، إما على طريقة Object وهي أن تستعمل الكلاس مباشرة باستعمال الدالة المشيِّدة Constructor Function أو أن تقوم بعمل كلاس فرعي من أي من الكلاسات الخاصة بهذا الأمر.

لعرض واجهة القائمة هناك خياران، إما أن نقوم باستعمال كلاس Activity أو كلاس ListActivity. فما الفرق بينهما:

  • كلاس Activity يمكن أن يحتوي واجهة القائمة مع واجهات رسومية أخرى كالواجهة النصية، أما كلاس ListActivity فهو يقوم بعرض القائمة على كافة الشاشة فتكون هي الواجهة الوحيدة المعروضة.
  • كلاس Activity يكون عاماً على عكس كلاس ListActivity الذي يكون خاصاً لواجهة القائمة ويكون أيضاً مجهز ببعض الدوال التي تساعد على عملية التحكم بالقائمة بشكل أسلس.
  • كلاس ListActivity هو كلاس متفرع من كلاس Activity فيمكن استعمال الدوال الخاصة بالإثنين عند استعماله.

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

android list view
في البداية نقوم بصنع الواجهة النصية الخاصة لكل صف في القائمة (قم بحفظ الواجهة في ملف وسمّه list_item.xml):

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="fill_parent"
 android:layout_height="fill_parent"
 android:padding="10dp"
 android:textSize="16sp" >
</TextView>

هذه الواجهة سوف تكون المسؤولة عن عرض كل صف في القائمة، وهذا لتسهيل عملية تحديث القائمة حيث يمكن التعديل على هذه الواجهة ليتم تغيير جميع الصفوف الموجودة في القائمة.

ثم نقوم بإنشاء المصفوفة التي تحتوي على المعلومات التي سوف يتم عرضها في القائمة:

 static final String[] COUNTRIES = new String[] {
"أفغانستان", "ألبانيا", "الجزائر", "ساموا الأمريكية",
"أندورا", "أنغولا", "أنجويلا", "أنتاركتيكا", "انتيغوا وبربودا",
"الأرجنتين", "أرمينيا", "اروبا", "استراليا", "النمسا", "أذربيجان",
 "جزر البهاما", "البحرين", "بنجلاديش", "باربادوس", "روسيا البيضاء",
 "بلجيكا", "بليز", "بنين", "برمودا", "بوتان", "بوليفيا", "البوسنة والهرسك",
 "بوتسوانا", "جزيرة بوفيت", "البرازيل", "إقليم المحيط الهندي البريطاني", "بروناي دار السلام",
 "بلغاريا", "بوركينا فاسو", "بوروندي", "كمبوديا", "الكاميرون", "كندا",
 "الرأس الأخضر", "جزر كايمان", "جمهورية افريقيا الوسطى", "تشاد", "تشيلي",
 "الصين", "جزيرة كريسماس", "كوكوس (كيلنغ)", "كولومبيا", "جزر القمر", "الكونغو",
 "الكونغو, وجمهورية الكونغو الديمقراطية", "جزر كوك", "كوستاريكا", "ساحل العاج",
 "كرواتيا (الاسم المحلي: هرفاتسكا)", "كوبا", "قبرص", "جمهورية التشيك", "الدنمارك",
 "جيبوتي", "دومينيكا", "جمهورية الدومينيكان", "تيمور الشرقية", "الاكوادور", "مصر",
 "السلفادور", "غينيا الاستوائية", "اريتريا", "استونيا", "اثيوبيا", "جزر فوكلاند (مالفيناس)",
 "جزر فارو", "فيجي", "فنل ندا", "فرنسا", "فرنسا, متروبوليتان", "جيانا الفرنسية",
 "بولينيزيا الفرنسية", "الأقاليم الجنوبية الفرنسية", "الجابون", "غامبيا", "جورجيا", "المانيا",
 "غانا", "جبل طارق", "اليونان", "غرينلاند", "غرينادا", "جوادلوب", "غوام",
 "غواتيمالا", "غينيا", "غينيا بيساو", "المملكة المتحدة", "الولايات المتحدة", "غيانا", "هايتي",
 "وسمع وماك دونالد جزر", "الكرسي الرسولي (دولة الفاتيكان)", "هندوراس", "هونج كونج", "المجر",
 "أيسلندا", "الهند", "اندونيسيا", "إيران (جمهورية الإسلامية)", "العراق", "ايرلندا",
 "ايطاليا", "جامايكا", "اليابان", "الاردن", "كازاخستان", "كينيا", "كيريباتي",
 "كوريا الديمقراطية الشعبية وجمهورية", "جمهورية كوريا", "الكويت", "قرغيزستان",
 "جمهورية لاو الديمقراطية", "لاتفيا", "لبنان", "ليسوتو", "ليبيريا", "ليبيا",
 "ليختنشتاين", "ليتوانيا", "لوكسمبورغ", "ماكاو", "مقدونيا, الجمهورية اليوغوسلافية السابقة من",
 "مدغشقر", "ملاوي", "ماليزيا", "جزر المالديف", "مالي", "مالطا",
 "جزر مارشال", "المارتينيك", "موريتانيا", "موريشيوس", "مايوت", "المكسيك",
 "ولايات ميكرونيزيا الموحدة من", "مولدافيا, الجمهورية", "موناكو", "منغوليا",
 "مونتسيرات", "المغرب",	 "موزمبيق", "ميانمار", "ناميبيا", "ناورو",
 "نيبال", "هولندا", "جزر الانتيل الهولندية", "كاليدونيا الجديدة", "نيوزيلندا",
 "نيكاراجوا", "النيجر", "نيجيريا", "نيوي", "جزيرة نورفولك",
 "جزر ماريانا الشمالية", "النرويج", "عمان", "باكستان", "بالاو",
 "بنما", "بابوا غينيا الجديدة", "باراجواي", "بيرو", "الفلبين", "بيتكيرن",
 "بولندا", "البرتغال", "بورتوريكو", "قطر", "ريونيون", "رومانيا",
 "الاتحاد الروسي", "رواندا", "سانت كيتس ونيفيس", "سانت لوسيا", "سانت فنسنت وغرينادين",
 "ساموا", "سان مارينو", "ساو تومي وبرينسيبي", "المملكة العربية السعودية", "السنغال",
 "سيشل", "سيراليون", "سنغافورة",	 "سلوفاكيا (جمهورية سلوفاكيا)", "سلوفينيا",
 "جزر سليمان", "الصومال", "جنوب أفريقيا", "ساندويتش الجنوبية جورجيا الجنوبية وجزر",
 "اسبانيا", "سريلانكا", "سانت هيلانة", "سان بيير وميكلون", "السودان", "سورينام",
 "جزر سفالبارد وجان ماين", "سوازيلاند", "السويد", "سويسرا", "سوريا", "تايوان",
 "طاجيكستان", "تنزانيا المتحدة, جمهورية", "تايلند", "توغو", "توكيلاو", "تونغا",
 "ترينيداد وتوباغو", "تونس", "تركيا", "تركمانستان", "جزر تركس وكايكوس", "توفالو",
 "أوغندا", "أوكرانيا", "الامارات العربية المتحدة", "الولايات المتحدة البعيدة الصغيرة جزر",
 "أوروغواي", "أوزبكستان", "فانواتو", "فنزويلا", "فيتنام", "جزر فيرجن (البريطانية)",
 "الجزر العذراء (الولايات المتحدة)", "واليس وفوتونا", "اليمن", "يوغوسلافيا", "زامبيا", "زيمبابوي"
   };

الخطوة التالية هي إنشاء الكلاس:

public class HelloListView extends ListActivity {
    @Override
     public void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);

	/*
	* نقوم بإنشاء الكائن الخاص بالمحوّل والذي يأخذ ثلاثة متغيرات الأول هو
	 * السياق، ووضعنا فيه this للتحديد بأن السياق الحالي هو المستعمل.
	* المتغير الثاني هو الواجهة النصية التي تستعمل لكل صف من صفوف القائمة.
	* وفيها نضع اسم الملف الذي قمنا بإنشائه قبل قليل. أما المتغير الثالث
	* فهو المصفوفة التي تحتوي على المعلومات المراد عرضها
	*/

	ArrayAdapter adapter = new ArrayAdapter(this, R.layout.list_item, COUNTRIES);
	setListAdapter(adapter);
}

بهذا تصبح القائمة الرسومية جاهزة للعرض. وسنقوم بإضافة أوامر معينة عند الضغط على أي من الصفوف في القائمة. للقيام بهذا سوف نستعمل واجهة Interface OnItemClickListener والتي تقوم بإضافة الدوال الخاصة بالتحكم بضغطات المستخدم على أي من الصفوف. بعد إضافة الواجهة للكلاس الذي قمنا بتصميمه قبل قليل ليصبح الكلاس بهذا الشكل:

public class HelloListView extends ListActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);

/* نقوم بإنشاء الكائن الخاص بالمحوّل والذي يأخذ ثلاثة متغيرات
الأول هو السياق، ووضعنا فيه this للتحديد بأن السياق الحالي هو
المستعمل. المتغير الثاني هو الواجهة النصية التي تستعمل لكل صف
من صفوف القائمة. وفيها نضع اسم الملف الذي قمنا بإنشائه قبل قليل.
أما المتغير الثالث فهو المصفوفة التي تحتوي على المعلومات المراد
عرضها */

ArrayAdapter adapter =
                     new ArrayAdapter(this, R.layout.list_item, COUNTRIES);

 // هذه الدالة تقوم بربط الكائن الخاص بالمحوّل
setListAdapter(adapter);

// نقوم هنا بإنشاء متغير للقائمة المعروضة حتى يمكننا من التعامل معها لاحقاً
 ListView lv = getListView();

// هنا نقوم بربط الواجهة بالقائمة، حتى يكون بإمكاننا
//وضع أوامر معينة عند الضغط على أحد الصفوف
lv.setOnItemClickListener(this);

// في هذه الدالة نقوم بوضع الأوامر التي نريد تفعيلها عند الضغط
// على كل صف توجد في الدالة أربعة متغيرات، الأول هو المحوّل،
// الثاني هو الواجهة الرسومية، والثالث هو موقع الصف من القائمة،
// والرابع هو رقم الصف

public void onItemClick(AdapterView parent, View view, int position, long id) {

// عند الضغط على الصف سوف يظهر مربع طافٍ وفيه محتوى الصف

Toast.makeText(getApplicationContext(),
               ((TextView) view).getText(), Toast.LENGTH_SHORT).show()});

}
}

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

<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="countries_array">
<item>البحرين</item>
<item>بنغلادش</item>
<item>باربادوس</item>
<item>بالاروس</item>
<item>بلجيكا</item>
<item>بليز</item>
<item>بنين</item>
</string-array>
</resources>

وقم بتغيير سطر المحوّل Adapter في الكلاس إلى هذا:

String[] countries = getResources().getStringArray(R.array.countries_array);
setListAdapter(new ArrayAdapter(this, R.layout.list_item, countries));

يمكنكم تحميل المشروع جاهزاً لبرنامج الـ Eclipse:

HelloAndroid

أتمنى أن تعجبكم هذه التدوينة، وأرجو سماع تعليقاتكم وآرائكم فيها.

تعليق

  1. يعطيك الف عافية استاذ عبدالقهاد, دائما معك بإذن الله

    وأتمنى أن تتكرم علينا بإنشاء حساب على تويتر لنتمكن من التواصل معكم دائما

    أسال الله لك التوفيق في حياتك وفي آخرتك

    • عبد القهار الحسني

      شكراً جزيلاً لك .. بالنسبة لتويتر فأنا لست من مستخدميه الدائمين .. ربما في المستقبل ان شاء الله

  2. Wael

    استفدت من شرحك كثير بس ادا ابغى اخليه كل عنصر يحولني على layout معين

اترك تعليقاً

الحقول المطلوبة موسومة بالعلامة *.