شرح ExpandableListView مع مثال في Android Studio
في Android ، يعد ExpandableListView طريقة عرض تُظهر عناصر في قائمة مستويين قابلة للتمرير عموديًا. تختلف عن listview عن طريق السماح للجماعات المستوى الثاني والتي يمكن توسيعها بشكل فردي لإظهار أبنائها. يمكن توسيع كل مجموعة أو طيها بشكل فردي لإظهار أو إخفاء عناصرها الفرعية.
يمكننا إرفاق أحداث المستمعين بـ ExpandableListView للاستماع إلى OnClick أو أي أحداث أخرى على المجموعة أو الأطفال الفرديين. تُستخدم المحولات لتزويد البيانات التي سيتم عرضها في ExpandableListView أو التحكم فيها .
ملاحظة مهمة: لا يمكنك استخدام القيمة wrap_content لسمة الارتفاع الخاصة بـ ExpandableListView في XML إذا لم يتم تحديد حجم الأصل بشكل صارم. بمعنى آخر ، إذا كان الوالد هو ScrollView ، فلا يمكنك تحديد wrap_content لأنه يمكن أن يكون بأي طول. ومع ذلك ، يمكنك استخدام محتوى الالتفاف إذا كان للأصل ExpandableListView حجم معين ، مثل 200 بكسل .
كود ExpandableListView في XML:
<ExpandableListView android:id="@+id/simpleExpandableListView" android:layout_width="fill_parent" android:layout_height="fill_parent"/>
جدول المحتويات
سمات وخصائص ExpandableListView في Android
الآن دعنا نناقش بعض السمات المهمة التي تساعدنا في تكوين ExpandableListView في ملف XML (التخطيط).
1. id: id هي سمة تُستخدم لتعريف طريقة عرض قائمة قابلة للتوسيع بشكل فريد.
<ExpandableListView android:id="@+id/simpleExpandableListView" android:layout_width="fill_parent" android:layout_height="fill_parent"/> <!-- id of an attribute used to uniquely identify a expandable list view -->
2. حاجز divider : هذا رسم أو لون يمكن رسمه بين عناصر قائمة المجموعة المختلفة.
أدناه نرسم مقسم اللون الأحمر بين عناصر المجموعة المختلفة.
<ExpandableListView android:id="@+id/simpleExpandableListView" android:layout_width="match_parent" android:layout_height="fill_parent" android:divider="#f00" android:dividerHeight="1dp" /> "/> <!-- red color divider with 1dp height between the groups items of expandable list view -->
3. dividerHeight: يحدد هذا ارتفاع الحاجز بين عناصر قائمة المجموعة. يمكن أن يكون هذا في dp (كثافة بكسل) ، sp (مقياس بكسل مستقل) أو بكسل (بكسل).
في المثال أعلاه للمقسم ، قمنا أيضًا بتعيين ارتفاع الحاجز 1dp بين عناصر القائمة. يجب أن يكون الارتفاع في dp أو sp أو px.
4. listSelector: تستخدم هذه الخاصية لتعيين محدد عرض القائمة القابلة للتوسيع. عادة ما يكون لونه برتقالي أو أزرق سماوي في الغالب ولكن يمكنك أيضًا تحديد لونك المخصص أو صورة كمحدد قائمة حسب التصميم الخاص بك.
يظهر لون المحدد أدناه باللون الأخضر ، وعند تحديد أي عنصر قائمة ، يصبح لون خلفية هذا العنصر باللون الأخضر.
<ExpandableListView android:id="@+id/simpleExpandableListView" android:layout_width="match_parent" android:layout_height="fill_parent" android:divider="#f00" android:dividerHeight="1dp" android:listSelector="#0f0" /> <!-- green color for the list selector item -->
5. childDivider: هذا هو رسم أو لون للرسم بين عناصر قائمة فرعية مختلفة لعرض قائمة قابلة للتوسيع.
أدناه نرسم فاصل اللون الأخضر بين العناصر الفرعية المختلفة للمجموعة.
<ExpandableListView android:id="@+id/simpleExpandableListView" android:layout_width="match_parent" android:layout_height="fill_parent" android:divider="#f00" android:dividerHeight="1dp" android:childDivider="#0f0" /> <!-- green color divider between the child items of expandable list view -->
الصورة أدناه مأخوذة من مثال ExpandableListView الموضح في نهاية هذا المنشور. في هذا قمنا بتعيين اللون الأخضر كمقسم فرعي واللون الأحمر كمقسم. سبب استخدامنا لهذه الصورة النموذجية لأننا نحتاج إلى تعبئة البيانات باستخدام المحول لتظهر لك سمة childDivider في العمل.
6. المساحة المتروكة padding : يتم استخدام خاصية المساحة المتروكة لتعيين المساحة المتروكة من اليسار أو اليمين أو أعلى أو أسفل.
- المساحة المتروكة لليمين paddingRight : اضبط المساحة المتروكة من الجانب الأيمن لعرض القائمة القابلة للتوسيع.
- المساحة المتروكة إلى اليسار paddingLeft : اضبط المساحة المتروكة من الجانب الأيسر لشريط التقدم .
- paddingTop: اضبط المساحة المتروكة من الجانب العلوي لعرض القائمة القابلة للتوسيع.
- paddingBottom: اضبط المساحة المتروكة من الجانب السفلي لعرض القائمة القابلة للتوسيع.
- المساحة المتروكة : اضبط المساحة المتروكة من جميع جوانب عرض القائمة القابلة للتوسيع.
أدناه قمنا بتعيين حشوة 50dp من جميع جوانب عرض القائمة القابلة للتوسيع.
<ExpandableListView android:id="@+id/simpleExpandableListView" android:layout_width="match_parent" android:layout_height="fill_parent" android:divider="#f00" android:dividerHeight="2dp" android:childDivider="#0f0" android:padding="50dp" /> <!-- 50 dp padding from all the sides of a expandable list view -->
المحول المستخدم في ExpandableListView في Android:
و محول هو جسر بين عنصر واجهة المستخدم ومصدر البيانات التي تساعدنا على تعبئة البيانات في عنصر واجهة المستخدم. إنه يحتفظ بالبيانات ويرسل البيانات إلى عرض المحول ، ثم يمكن للعرض أن يأخذ البيانات من عرض المحول ويعرض البيانات على طرق عرض مختلفة مثل ExpandableListView أو طرق عرض أخرى. سيوفر تنفيذ هذه الواجهة الوصول إلى بيانات الأطفال (مصنفة حسب المجموعات) ، وأيضًا إنشاء مناظر للأطفال والمجموعات.
في Android لتزويد البيانات في ExpandableListView ، يتم استخدام المحولات التالية.
1. ExpandableListAdapter
2. BaseExpandableListAdapter
3. SimpleExpandableListAdapter
الآن نوضح هذه المحولات الثلاثة بالتفصيل:
1. ExpandableListAdapter:
ExpandableListAdapter هو محول يربط ExpandableListView بالبيانات الأساسية. سيؤدي تنفيذ هذه الواجهة إلى توفير البيانات للأطفال وكذلك بدء وجهات النظر للأطفال والمجموعات. لتخصيص القائمة ، نحتاج إلى تنفيذ ExpandableListAdapter في المحول المخصص الخاص بنا.
يوجد أدناه مثال لرمز ExpandableListAdapter الذي أنشأنا فيه فئة CustomAdapter ثم ننفذ ExpandableListAdapter في تلك الفئة.
public class CustomAdapter implements ExpandableListAdapter { @Override public void registerDataSetObserver(DataSetObserver observer) { } @Override public void unregisterDataSetObserver(DataSetObserver observer) { } @Override public int getGroupCount() { return 0; } @Override public int getChildrenCount(int groupPosition) { return 0; } @Override public Object getGroup(int groupPosition) { return null; } @Override public Object getChild(int groupPosition, int childPosition) { return null; } @Override public long getGroupId(int groupPosition) { return 0; } @Override public long getChildId(int groupPosition, int childPosition) { return 0; } @Override public boolean hasStableIds() { return false; } @Override public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) { return null; } @Override public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) { return null; } @Override public boolean isChildSelectable(int groupPosition, int childPosition) { return false; } @Override public boolean areAllItemsEnabled() { return false; } @Override public boolean isEmpty() { return false; } @Override public void onGroupExpanded(int groupPosition) { } @Override public void onGroupCollapsed(int groupPosition) { } @Override public long getCombinedChildId(long groupId, long childId) { return 0; } @Override public long getCombinedGroupId(long groupId) { return 0; } }
اقرأ البرنامج التعليمي ExpandableListAdapter مع مثال في Android Studio لمزيد من التفاصيل.
2. BaseExpandableListAdapter:
BaseExpandableListAdapter هو فئة أساسية لمحول القائمة القابل للتوسيع المستخدم لتوفير البيانات وطرق العرض من بعض البيانات إلى ExpandableListView. لإنشاء ExpandableListView مخصص ، نحتاج إلى إنشاء فئة مخصصة ثم توسيع فئة BaseExpandableListAdapter في تلك الفئة.
يوجد أدناه مثال على رمز BaseExpandableListAdapter الذي نقوم فيه بإنشاء فئة محول مخصصة ثم نقوم بتوسيع BaseExpandableListAdapter في تلك الفئة.
public class CustomAdapter extends BaseExpandableListAdapter { @Override public int getGroupCount() { return 0; } @Override public int getChildrenCount(int groupPosition) { return 0; } @Override public Object getGroup(int groupPosition) { return null; } @Override public Object getChild(int groupPosition, int childPosition) { return null; } @Override public long getGroupId(int groupPosition) { return 0; } @Override public long getChildId(int groupPosition, int childPosition) { return 0; } @Override public boolean hasStableIds() { return false; } @Override public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) { return null; } @Override public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) { return null; } @Override public boolean isChildSelectable(int groupPosition, int childPosition) { return false; } }
اقرأ BaseExpandableListAdapter مع مثال في Android Studio لشرح كل هذه الوظائف.
3. SimpleExpandableListAdapter:
SimpleExpandableListAdapter هو محول يتم استخدامه لتعيين البيانات الثابتة إلى طرق العرض المجمعة والطفل المحددة في ملف XML (التخطيط) الخاص بنا. يمكننا تحديد دعم البيانات للمجموعة بشكل منفصل كقائمة خرائط. يتوافق كل إدخال في ArrayList مع مجموعة واحدة في القائمة القابلة للتوسيع. تحتوي الخرائط على بيانات لكل صف. يمكننا أيضًا تحديد ملف XML الذي يحدد طرق العرض المستخدمة لعرض مجموعة ، وتعيين من المفاتيح الموجودة في الخريطة إلى طرق عرض محددة. تتشابه هذه العملية مع الطفل ، إلا أنها بمستوى واحد أعمق بحيث يتم تحديد دعم البيانات كقائمة <قائمة> ، حيث تتوافق القائمة الأولى مع مجموعة الطفل والقائمة الثانية تتوافق مع وضع الطفل داخل تلك المجموعة ، وفي النهاية تحتوي الخريطة على بيانات الطفل المعين.
public SimpleExpandableListAdapter (Context context, List<? extends Map<String, ?>> groupData, int groupLayout, String[]groupFrom, int[] groupTo, List<? extends List<? extends Map<String, ?>>> childData, int childLayout, String[] childFrom, int[] childTo)
اقرأ البرنامج التعليمي SimpleExpandableListAdapter للحصول على شرح لجميع هذه المعلمات.
ExpandableListView باستخدام مثال BaseExpandableListAdapter في Android Studio
يوجد أدناه مثال ExpandableListView في android حيث نعرض قائمة قابلة للتوسيع مع اسم الموضوع وموضوعاته. في هذا المثال ، نعرض أسماء الموضوعات كعناصر مجموعة وأسماء موضوعاتها كعناصر فرعية لمجموعة معينة. في هذا نقوم بتنفيذ أحداث setOnChildClickListener () و setOnGroupClickListener () وكلما نقر المستخدم على طفل أو عنصر مجموعة ، يتم عرض اسم العنصر باستخدام Toast.
يمكنك أدناه تنزيل الكود ، والاطلاع على الإخراج النهائي والشرح خطوة بخطوة للمثال في Android Studio:

الخطوة 1: قم بإنشاء مشروع جديد وقم بتسميته ExpandableListViewExample.
الخطوة 2: افتح res -> layout -> activity_main.xml (أو) main.xml وأضف الكود التالي:
في هذه الخطوة ، نفتح ملف XML ونضيف الكود لعرض ExpandableListView باستخدام سماته المختلفة.
<?xml version="1.0" encoding="UTF-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <ExpandableListView android:id="@+id/simpleExpandableListView" android:layout_width="match_parent" android:layout_height="fill_parent" android:divider="#f00" android:childDivider="#0f0" android:dividerHeight="1dp" /> </RelativeLayout>
الخطوة 3: إنشاء ملف xml جديد لعناصر المجموعة فتح res -> layout -> group_items.xml وأضف الكود التالي:
في هذه الخطوة نضيف الكود لعرض أسماء موضوع TextView .
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="55dip" android:orientation="vertical" > <TextView android:id="@+id/heading" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingLeft="35sp" android:textAppearance="?android:attr/textAppearanceLarge" android:textStyle="bold" /> </LinearLayout>
الخطوة 4: إنشاء ملف xml جديد لعناصر المجموعة فتح res -> layout -> child_items.xml وأضف الكود التالي:
في هذه الخطوة نضيف الكود الخاص بعرض نصي TextView ، أحدهما لتسلسل الموضوعات والآخر لاسم الموضوع
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" xmlns:android="http://schemas.android.com/apk/res/android"> <TextView android:id="@+id/sequence" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_alignParentTop="true" android:paddingLeft="35sp" android:textAppearance="?android:attr/textAppearanceMedium" /> <TextView android:id="@+id/childItem" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_toRightOf="@id/sequence" android:textAppearance="?android:attr/textAppearanceMedium" /> </RelativeLayout>
الخطوة 5: افتح src -> package -> MainActivity. جافا
في هذه الخطوة ، نفتح MainActivity ونضيف الكود لبدء ExpandableListView ونضيف البيانات إلى القوائم للعرض في ExpandableListView باستخدام فئات النموذج ثم نضبط المحول الذي يملأ البيانات في ExpandableListView. في هذا نقوم بتنفيذ أحداث setOnChildClickListener () و setOnGroupClickListener (). عندما ينقر المستخدم على طفل أو عنصر مجموعة ، يتم عرض اسم العنصر باستخدام Toast.
package example.abhiandroid.expandablelistviewexample; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.ExpandableListView; import android.widget.Toast; import java.util.ArrayList; import java.util.LinkedHashMap; public class MainActivity extends AppCompatActivity{ private LinkedHashMap<String, GroupInfo> subjects = new LinkedHashMap<String, GroupInfo>(); private ArrayList<GroupInfo> deptList = new ArrayList<GroupInfo>(); private CustomAdapter listAdapter; private ExpandableListView simpleExpandableListView; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // add data for displaying in expandable list view loadData(); //get reference of the ExpandableListView simpleExpandableListView = (ExpandableListView) findViewById(R.id.simpleExpandableListView); // create the adapter by passing your ArrayList data listAdapter = new CustomAdapter(MainActivity.this, deptList); // attach the adapter to the expandable list view simpleExpandableListView.setAdapter(listAdapter); //expand all the Groups expandAll(); // setOnChildClickListener listener for child row click simpleExpandableListView.setOnChildClickListener(new ExpandableListView.OnChildClickListener() { @Override public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) { //get the group header GroupInfo headerInfo = deptList.get(groupPosition); //get the child info ChildInfo detailInfo = headerInfo.getProductList().get(childPosition); //display it or do something with it Toast.makeText(getBaseContext(), " Clicked on :: " + headerInfo.getName() + "/" + detailInfo.getName(), Toast.LENGTH_LONG).show(); return false; } }); // setOnGroupClickListener listener for group heading click simpleExpandableListView.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() { @Override public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) { //get the group header GroupInfo headerInfo = deptList.get(groupPosition); //display it or do something with it Toast.makeText(getBaseContext(), " Header is :: " + headerInfo.getName(), Toast.LENGTH_LONG).show(); return false; } }); } //method to expand all groups private void expandAll() { int count = listAdapter.getGroupCount(); for (int i = 0; i < count; i++){ simpleExpandableListView.expandGroup(i); } } //method to collapse all groups private void collapseAll() { int count = listAdapter.getGroupCount(); for (int i = 0; i < count; i++){ simpleExpandableListView.collapseGroup(i); } } //load some initial data into out list private void loadData(){ addProduct("Android","ListView"); addProduct("Android","ExpandableListView"); addProduct("Android","GridView"); addProduct("Java","PolyMorphism"); addProduct("Java","Collections"); } //here we maintain our products in various departments private int addProduct(String department, String product){ int groupPosition = 0; //check the hash map if the group already exists GroupInfo headerInfo = subjects.get(department); //add the group if doesn't exists if(headerInfo == null){ headerInfo = new GroupInfo(); headerInfo.setName(department); subjects.put(department, headerInfo); deptList.add(headerInfo); } //get the children for the group ArrayList<ChildInfo> productList = headerInfo.getProductList(); //size of the children list int listSize = productList.size(); //add to the counter listSize++; //create a new child and add that to the group ChildInfo detailInfo = new ChildInfo(); detailInfo.setSequence(String.valueOf(listSize)); detailInfo.setName(product); productList.add(detailInfo); headerInfo.setProductList(productList); //find the group position inside the list groupPosition = deptList.indexOf(headerInfo); return groupPosition; } }
الخطوة 6: إنشاء فئة جديدة افتح -> حزمة -> GroupInfo. جافا وأضف الكود التالي.
في هذه الخطوة ، نقوم بإنشاء فصل لإعداد والحصول على اسم عنصر المجموعة ومعلومات العناصر الفرعية وفقًا لمجموعة معينة. GroupInfo هي فئة نموذج تُستخدم لتعيين اسم عنصر المجموعة ومعلومات العناصر الفرعية من نشاطك الرئيسي ثم الحصول على المعلومات داخل فئة المحول. أخيرًا قم بتعيين القيمة إلى ExpandableListView.
package example.abhiandroid.expandablelistviewexample; import java.util.ArrayList; public class GroupInfo { private String name; private ArrayList<ChildInfo> list = new ArrayList<ChildInfo>(); public String getName() { return name; } public void setName(String name) { this.name = name; } public ArrayList<ChildInfo> getProductList() { return list; } public void setProductList(ArrayList<ChildInfo> productList) { this.list = productList; } }
الخطوة 7: إنشاء فصل جديد افتح -> حزمة -> ChildInfo. جافا وأضف الكود التالي.
في هذه الخطوة ، نقوم بإنشاء فئة لإعداد والحصول على الاسم والتسلسل للعناصر التابعة. ChildInfo هو فئة نموذج تُستخدم لتعيين اسم العنصر الفرعي وتسلسل العنصر الفرعي من نشاطك الرئيسي ثم الحصول على الاسم والتسلسل داخل فئة المحول. أخيرًا ، قم بتعيين القيمة إلى عرض القائمة القابل للتوسيع.
package example.abhiandroid.expandablelistviewexample; public class ChildInfo { private String sequence = ""; private String name = ""; public String getSequence() { return sequence; } public void setSequence(String sequence) { this.sequence = sequence; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
الخطوة 8: قم بإنشاء فئة جديدة Open -> package -> CustomAdapter.Java وأضف الكود التالي.
في هذه الخطوة ، نقوم بإنشاء فئة CustomAdapter ثم توسيع BaseExpandableListAdapter في تلك الفئة. أخيرًا ، قم بتعيين البيانات في ExpandableListView من فئة نموذج GroupInfo و ChildInfo.
package example.abhiandroid.expandablelistviewexample; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseExpandableListAdapter; import android.widget.TextView; import java.util.ArrayList; /** * Created by Gourav on 08-03-2016. */ public class CustomAdapter extends BaseExpandableListAdapter { private Context context; private ArrayList<GroupInfo> deptList; public CustomAdapter(Context context, ArrayList<GroupInfo> deptList) { this.context = context; this.deptList = deptList; } @Override public Object getChild(int groupPosition, int childPosition) { ArrayList<ChildInfo> productList = deptList.get(groupPosition).getProductList(); return productList.get(childPosition); } @Override public long getChildId(int groupPosition, int childPosition) { return childPosition; } @Override public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View view, ViewGroup parent) { ChildInfo detailInfo = (ChildInfo) getChild(groupPosition, childPosition); if (view == null) { LayoutInflater infalInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); view = infalInflater.inflate(R.layout.child_items, null); } TextView sequence = (TextView) view.findViewById(R.id.sequence); sequence.setText(detailInfo.getSequence().trim() + ". "); TextView childItem = (TextView) view.findViewById(R.id.childItem); childItem.setText(detailInfo.getName().trim()); return view; } @Override public int getChildrenCount(int groupPosition) { ArrayList<ChildInfo> productList = deptList.get(groupPosition).getProductList(); return productList.size(); } @Override public Object getGroup(int groupPosition) { return deptList.get(groupPosition); } @Override public int getGroupCount() { return deptList.size(); } @Override public long getGroupId(int groupPosition) { return groupPosition; } @Override public View getGroupView(int groupPosition, boolean isLastChild, View view, ViewGroup parent) { GroupInfo headerInfo = (GroupInfo) getGroup(groupPosition); if (view == null) { LayoutInflater inf = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); view = inf.inflate(R.layout.group_items, null); } TextView heading = (TextView) view.findViewById(R.id.heading); heading.setText(headerInfo.getName().trim()); return view; } @Override public boolean hasStableIds() { return true; } @Override public boolean isChildSelectable(int groupPosition, int childPosition) { return true; } }
المخرجات :
قم الآن بتشغيل التطبيق وسترى الموضوعات الرئيسية والمواضيع الفرعية المدرجة في ExpandableListView.