Android 中關於ExpandableListView的簡單使用,以一個demo為例,比較簡單,主要用於理解一些概念性的知識。僅作為學習筆記。
1、定義:可擴展的ListView。
public class ExpandableListView extends ListView { ...... }
繼承自ListView,因此基本使用方法同ListView:
(1)需要自定義一個繼承自BaseExpandableListAdapter的Adapter;當然包括相關的布局等。
(2)注冊監聽事件;
由於該例子很簡單,直接查看代碼及注釋,更清晰的顯示常用方法的作用,在此不再詳述。
2、基本用法:
//主界面布局: <Button android:id="@+id/expandBtn" android:textSize="18sp" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/expandable_des" /> <ExpandableListView android:layout_marginTop="10dp" android:id="@+id/expandableListView" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/bg_default" android:groupIndicator="@null" android:visibility="gone" ></ExpandableListView> <!-- android:groupIndicator="@null" 去掉系統自帶的展開圖標 -->
1 //自定義適配器ExpandAdapter.java 2 public class ExpandAdapter extends BaseExpandableListAdapter { 3 private final String TAG = "ExpandAdapter"; 4 5 private Context mContext; 6 private LayoutInflater layoutInflater; 7 8 private String[] groupNames = new String[] 9 {"C++","JAVA","Android","HTML"}; 10 11 // private Drawable leftDrawable; //具體看本文末尾補充部分 12 private int arrowUpId,arrowDownId; 13 14 public ExpandAdapter(Context context) { 15 // TODO Auto-generated constructor stub 16 mContext = context; 17 layoutInflater = LayoutInflater.from(mContext); 18 19 arrowUpId = R.drawable.arrow_up; 20 arrowDownId = R.drawable.arrow_down; 21 22 // leftDrawable = context.getDrawable(R.drawable.ic_launcher); 23 // leftDrawable.setBounds(0, 0, leftDrawable.getMinimumWidth(), leftDrawable.getMinimumHeight()); 24 } 25 26 @Override 27 public Object getChild(int arg0, int arg1) { 28 // TODO Auto-generated method stub 29 return null; 30 } 31 32 @Override 33 public long getChildId(int arg0, int arg1) { 34 // TODO Auto-generated method stub 35 return arg1; 36 } 37 38 @Override 39 public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View childView, 40 ViewGroup parent) { //子項布局 41 // TODO Auto-generated method stub 42 ChildHolder childHolder; 43 44 if(childView == null){ 45 childView = layoutInflater.inflate(R.layout.child_view, null); 46 childHolder = new ChildHolder(); 47 childHolder.child_content = (TextView) childView.findViewById(R.id.child_content); 48 childView.setTag(childHolder); 49 }else{ 50 childHolder = (ChildHolder) childView.getTag(); 51 } 52 53 // Log.d(TAG, "getChildView groupPos: " + groupPosition + " childPos: " + childPosition); 54 55 // if(groupPosition < groupNames.length){ 56 // groupHolder.name_type.setText(groupNames[groupPosition]); 57 // } 58 59 // if(childPosition % 2 == 0){ 60 // childHolder.child_content.setText("使用 drawableLeft getChildView getChildView getChildView getChildView"); 61 // childHolder.child_content.setCompoundDrawables(leftDrawable, null, null, null); 62 // } 63 64 return childView; 65 } 66 67 @Override 68 public int getChildrenCount(int arg0) { //子項總數 69 return 5; 70 } 71 72 @Override 73 public Object getGroup(int arg0) { 74 return groupNames[arg0]; 75 } 76 77 @Override 78 public int getGroupCount() { //一級列表項數 79 return groupNames.length; 80 } 81 82 @Override 83 public long getGroupId(int groupPosition) { 84 return groupPosition; 85 } 86 87 @Override 88 public View getGroupView(int groupPosition, boolean isExpand, View convertView, ViewGroup parent) {//一級列表項 89 // TODO Auto-generated method stub 90 GroupHolder groupHolder; 91 92 if(convertView == null){ 93 convertView = layoutInflater.inflate(R.layout.grounp_view, null); 94 groupHolder = new GroupHolder(); 95 groupHolder.img_type = (ImageView) convertView.findViewById(R.id.img_type); 96 groupHolder.name_type = (TextView) convertView.findViewById(R.id.name_type); 97 groupHolder.img_arrow = (ImageView) convertView.findViewById(R.id.img_arrow); 98 convertView.setTag(groupHolder); 99 }else{ 100 groupHolder = (GroupHolder) convertView.getTag(); 101 } 102 103 if(isExpand){ 104 // groupHolder.img_arrow.setImageResource(R.drawable.arrow_up); 105 groupHolder.img_arrow.setImageResource(arrowUpId); 106 }else{ 107 // groupHolder.img_arrow.setImageResource(R.drawable.arrow_down); 108 groupHolder.img_arrow.setImageResource(arrowDownId); 109 } 110 111 Log.i(TAG, "getGroupView groupPosition: " + groupPosition + " isExpand: " + isExpand); 112 113 if(groupPosition < groupNames.length){ 114 groupHolder.name_type.setText(groupNames[groupPosition]); 115 } 116 117 return convertView; 118 } 119 120 @Override 121 public boolean hasStableIds() { 122 return false; 123 } 124 125 //為了使子項響應點擊事件,此處必須返回true!!!!!!!!!!!!!!!!!!!!!!!!!!! 126 @Override 127 public boolean isChildSelectable(int arg0, int arg1) { 128 // TODO Auto-generated method stub 129 return true; 130 } 131 132 class GroupHolder{ 133 ImageView img_type,img_arrow; 134 TextView name_type; 135 } 136 class ChildHolder{ 137 TextView child_content; 138 } 139 140 }
1 ExpandableListViewActivity中的基本使用: 2 3 expandableListView = (ExpandableListView) findViewById(R.id.expandableListView); 4 5 expandAdapter = new ExpandAdapter(this); 6 expandableListView.setAdapter(expandAdapter); 7 8 //注冊監聽事件: 9 private void initExpandableListener(){ 10 expandableListView.setOnGroupClickListener(new OnGroupClickListener() { 11 @Override 12 public boolean onGroupClick(ExpandableListView expandableListView, View arg1, int groupPosition, 13 long arg3) { //組(一級列表)點擊事件 默認return false;若設為true,表示點擊列表不會展開 14 // TODO Auto-generated method stub 15 Log.i(TAG, "onGroupClick " + groupPosition); 16 17 return false; 18 } 19 }); 20 expandableListView.setOnGroupCollapseListener(new OnGroupCollapseListener() { 21 @Override 22 public void onGroupCollapse(int groupPosition) { //折疊 23 // TODO Auto-generated method stub 24 Log.i(TAG, "onGroupCollapse " + groupPosition); 25 26 } 27 }); 28 expandableListView.setOnGroupExpandListener(new OnGroupExpandListener() { 29 @Override 30 public void onGroupExpand(int groupPosition) { //展開 若需要展開某項,其他項關閉,可在該處理方法中寫入相應邏輯 31 // TODO Auto-generated method stub 32 Log.i(TAG, "onGroupExpand " + groupPosition); 33 34 } 35 }); 36 37 38 //Child 39 expandableListView.setOnChildClickListener(new OnChildClickListener() { 40 41 @Override 42 public boolean onChildClick(ExpandableListView arg0, View arg1, int groupPosition, 43 int childPosition, long arg4) { 44 // TODO Auto-generated method stub 45 Log.i(TAG, "onChildClick " + groupPosition + " " + childPosition); 46 47 return false; 48 } 49 }); 50 51 52 //添加一個按鈕,用於測試expandGroup(int groupPos, boolean animate)中的animate不同值的顯示效果. 53 Button expandBtn = (Button) findViewById(R.id.expandBtn); 54 expandBtn.setOnClickListener(new OnClickListener() { 55 @Override 56 public void onClick(View v) { 57 // TODO Auto-generated method stub 58 expandableListView.expandGroup(3, false); //展開時,是否執行滑動過程; 建議在測試時,選擇展開后列表能夠超出屏幕的,更容易看到兩者不同 59 //看源碼,發現為true時執行了方法smoothScrollToPosition(position, boundPosition) 60 //在默認情況下,點擊group選項,系統也會執行上述smoothScrollToPosition方法. 61 62 } 63 }); 64 65 }
函數expandGroup(int groupPos, boolean animate)的執行效果:

默認界面 animate=false animate=true
3、注意事項:
a.寫布局時,為了去掉系統自帶的展開圖標(上下箭頭),需設置ExpandableListView的android:groupIndicator="@null"
b.可展開列表的適配器一般自定義,並繼承自BaseExpandableListAdapter。當然,對於一些簡單的數據或布局,可直接使用SimpleExpandableListAdapter或SimpleCursorTreeAdapter。
c.可以讓Activity繼承ExpandableListActivity,這樣在Activity即可重寫相關點擊事件的方法.因為ExpandableListActivity實現了這些方法的接口。
d.若讓子項響應點擊事件,必須在ExpandAdapter中設置isChildSelectable()方法返回true。
4、補充:
上述demo中的子項布局很簡單,因為是簡單的測試,所以只在布局中定義了一個TextView,圖片使用了android:drawableLeft,在ExpandAdapter中可以看到還保留有在代碼中設置圖片的代碼(注釋的部分line),以下就總結以下用法:
//子項布局child_view.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:paddingTop="10dp" android:paddingBottom="10dp" > <TextView android:id="@+id/child_content" android:layout_width="wrap_content" android:layout_height="50dp" android:layout_marginStart="5dp" android:drawableLeft="@drawable/ic_launcher" android:ellipsize="end" android:gravity="center_vertical" android:text="child name" android:textSize="20sp" android:singleLine="true" android:maxLength="30" /> </LinearLayout>
總結:android中,若圖標+文字確定的,則可使用TextView一個控件來實現,利用drawableLeft/drawableTop...等。但,若圖標不確定,需要在代碼中動態設置,則建議分開寫,ImageView + TextView 。
因,在代碼中設置圖標很麻煩,需要以下三步:
(1) leftDrawable(獲取Drawable對象)
(2) leftDrawable.setBounds(0, 0, leftDrawable.getMinimumWidth(), leftDrawable.getMinimumHeight());
(3) childHolder.child_content.setCompoundDrawables(leftDrawable, null, null, null);