在某些android开发群里,看到有些新手问怎么实现QQ好友列表,其实网上一搜挺多的。接触Android,也才一年的时间,大部分时间花在工作上(解bug。。。),界面上开发很少参与。自己维护的系统应用里,有个ExpandableListView的界面(其实android例子APIDemo也有类似的例子)就在这里写个Demo供新手参考。

ExpandableListView的用法:难点就是重写BaseExpandableListAdapter及提供的数据源。

下面看看继承BaseExpandableListAdapter的适配器:

[java] view plain copy
  1. <spanxmlns="http://www.w3.org/1999/xhtml">packagecom.xyz.expande;
  2. importjava.util.List;
  3. importandroid.app.AlertDialog;
  4. importandroid.content.Context;
  5. importandroid.graphics.Bitmap;
  6. importandroid.graphics.Bitmap.Config;
  7. importandroid.graphics.Canvas;
  8. importandroid.graphics.Paint;
  9. importandroid.graphics.PixelFormat;
  10. importandroid.graphics.PorterDuff.Mode;
  11. importandroid.graphics.PorterDuffXfermode;
  12. importandroid.graphics.Rect;
  13. importandroid.graphics.RectF;
  14. importandroid.graphics.drawable.BitmapDrawable;
  15. importandroid.graphics.drawable.Drawable;
  16. importandroid.util.Log;
  17. importandroid.view.LayoutInflater;
  18. importandroid.view.View;
  19. importandroid.view.ViewGroup;
  20. importandroid.widget.BaseExpandableListAdapter;
  21. importandroid.widget.ImageView;
  22. importandroid.widget.TextView;
  23. publicclassExpandeAdapterextendsBaseExpandableListAdapter{
  24. privateContextmContext;
  25. privateLayoutInflatermInflater=null;
  26. privateString[]mGroupStrings=null;
  27. privateList<List<Item>>mData=null;
  28. publicExpandeAdapter(Contextctx,List<List<Item>>list){
  29. mContext=ctx;
  30. mInflater=(LayoutInflater)mContext
  31. .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
  32. mGroupStrings=mContext.getResources().getStringArray(R.array.groups);
  33. mData=list;
  34. }
  35. publicvoidsetData(List<List<Item>>list){
  36. mData=list;
  37. }
  38. @Override
  39. publicintgetGroupCount(){
  40. //TODOAuto-generatedmethodstub
  41. returnmData.size();
  42. }
  43. @Override
  44. publicintgetChildrenCount(intgroupPosition){
  45. //TODOAuto-generatedmethodstub
  46. returnmData.get(groupPosition).size();
  47. }
  48. @Override
  49. publicList<Item>getGroup(intgroupPosition){
  50. //TODOAuto-generatedmethodstub
  51. returnmData.get(groupPosition);
  52. }
  53. @Override
  54. publicItemgetChild(intgroupPosition,intchildPosition){
  55. //TODOAuto-generatedmethodstub
  56. returnmData.get(groupPosition).get(childPosition);
  57. }
  58. @Override
  59. publiclonggetGroupId(intgroupPosition){
  60. //TODOAuto-generatedmethodstub
  61. returngroupPosition;
  62. }
  63. @Override
  64. publiclonggetChildId(intgroupPosition,intchildPosition){
  65. //TODOAuto-generatedmethodstub
  66. returnchildPosition;
  67. }
  68. @Override
  69. publicbooleanhasStableIds(){
  70. //TODOAuto-generatedmethodstub
  71. returnfalse;
  72. }
  73. @Override
  74. publicViewgetGroupView(intgroupPosition,booleanisExpanded,
  75. ViewconvertView,ViewGroupparent){
  76. //TODOAuto-generatedmethodstub
  77. if(convertView==null){
  78. convertView=mInflater.inflate(R.layout.group_item_layout,null);
  79. }
  80. GroupViewHolderholder=newGroupViewHolder();
  81. holder.mGroupName=(TextView)convertView
  82. .findViewById(R.id.group_name);
  83. holder.mGroupName.setText(mGroupStrings[groupPosition]);
  84. holder.mGroupCount=(TextView)convertView
  85. .findViewById(R.id.group_count);
  86. holder.mGroupCount.setText("["+mData.get(groupPosition).size()+"]");
  87. returnconvertView;
  88. }
  89. @Override
  90. publicViewgetChildView(intgroupPosition,intchildPosition,
  91. booleanisLastChild,ViewconvertView,ViewGroupparent){
  92. //TODOAuto-generatedmethodstub
  93. if(convertView==null){
  94. convertView=mInflater.inflate(R.layout.child_item_layout,null);
  95. }
  96. ChildViewHolderholder=newChildViewHolder();
  97. holder.mIcon=(ImageView)convertView.findViewById(R.id.img);
  98. holder.mIcon.setBackgroundDrawable(getRoundCornerDrawable(
  99. getChild(groupPosition,childPosition).getImageId(),10));
  100. holder.mChildName=(TextView)convertView.findViewById(R.id.item_name);
  101. holder.mChildName.setText(getChild(groupPosition,childPosition)
  102. .getName());
  103. holder.mDetail=(TextView)convertView.findViewById(R.id.item_detail);
  104. holder.mDetail.setText(getChild(groupPosition,childPosition)
  105. .getDetail());
  106. returnconvertView;
  107. }
  108. @Override
  109. publicbooleanisChildSelectable(intgroupPosition,intchildPosition){
  110. //TODOAuto-generatedmethodstub
  111. /*很重要:实现ChildView点击事件,必须返回true*/
  112. returntrue;
  113. }
  114. privateDrawablegetRoundCornerDrawable(intresId,floatroundPX/*圆角的半径*/){
  115. Drawabledrawable=mContext.getResources().getDrawable(resId);
  116. intw=mContext.getResources().getDimensionPixelSize(R.dimen.image_width);
  117. inth=w;
  118. Bitmapbitmap=Bitmap
  119. .createBitmap(w,h,
  120. drawable.getOpacity()!=PixelFormat.OPAQUE?Bitmap.Config.ARGB_8888
  121. :Bitmap.Config.RGB_565);
  122. Canvascanvas=newCanvas(bitmap);
  123. drawable.setBounds(0,0,w,h);
  124. drawable.draw(canvas);
  125. intwidth=bitmap.getWidth();
  126. intheight=bitmap.getHeight();
  127. BitmapretBmp=Bitmap.createBitmap(width,height,Config.ARGB_8888);
  128. Canvascan=newCanvas(retBmp);
  129. finalintcolor=0xff424242;
  130. finalPaintpaint=newPaint();
  131. finalRectrect=newRect(0,0,width,height);
  132. finalRectFrectF=newRectF(rect);
  133. paint.setColor(color);
  134. paint.setAntiAlias(true);
  135. can.drawARGB(0,0,0,0);
  136. can.drawRoundRect(rectF,roundPX,roundPX,paint);
  137. paint.setXfermode(newPorterDuffXfermode(Mode.SRC_IN));
  138. can.drawBitmap(bitmap,rect,rect,paint);
  139. returnnewBitmapDrawable(retBmp);
  140. }
  141. privateclassGroupViewHolder{
  142. TextViewmGroupName;
  143. TextViewmGroupCount;
  144. }
  145. privateclassChildViewHolder{
  146. ImageViewmIcon;
  147. TextViewmChildName;
  148. TextViewmDetail;
  149. }
  150. }
  151. </span>
里面用到的有两个布局,GroupView(ChildViewt没展开的情况)如图:

布局group_item_layout.xml如下:

[html] view plain copy
  1. <?xmlversion="1.0"encoding="utf-8"?>
  2. <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="match_parent"
  4. android:layout_height="?android:attr/listPreferredItemHeight"
  5. android:orientation="horizontal">
  6. <TextView
  7. android:id="@+id/group_name"
  8. android:layout_width="wrap_content"
  9. android:layout_height="?android:attr/listPreferredItemHeight"
  10. android:textAppearance="?android:attr/textAppearanceMedium"
  11. android:layout_marginLeft="35dip"
  12. android:gravity="center_vertical"
  13. android:singleLine="true"/>
  14. <TextView
  15. android:id="@+id/group_count"
  16. android:layout_width="wrap_content"
  17. android:layout_height="?android:attr/listPreferredItemHeight"
  18. android:textAppearance="?android:attr/textAppearanceMedium"
  19. android:layout_marginLeft="5dip"
  20. android:gravity="center_vertical"
  21. android:singleLine="true"/>
  22. </LinearLayout>

另外一个就是ChildView,本例仿QQ好友列表,如图:


哈哈,熟悉吧。布局child_item_layout.xml如下:

[html] view plain copy
  1. <?xmlversion="1.0"encoding="utf-8"?>
  2. <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="fill_parent"
  4. android:layout_height="wrap_content"
  5. android:minHeight="@dimen/min_Height"
  6. <spanstyle="color:#ff0000;">android:descendantFocusability="blocksDescendants"
  7. </span>android:orientation="horizontal">
  8. <ImageView
  9. android:id="@+id/img"
  10. android:layout_width="@dimen/image_width"
  11. android:layout_height="@dimen/image_width"
  12. android:layout_marginLeft="2dip"
  13. android:layout_marginRight="10dip"
  14. android:layout_gravity="center_vertical"/>
  15. <LinearLayout
  16. android:layout_width="wrap_content"
  17. android:layout_height="match_parent"
  18. android:orientation="vertical">
  19. <TextView
  20. android:id="@+id/item_name"
  21. android:layout_width="wrap_content"
  22. android:layout_height="0.0dip"
  23. android:gravity="center_vertical"
  24. android:layout_weight="1"/>
  25. <TextView
  26. android:id="@+id/item_detail"
  27. android:layout_width="wrap_content"
  28. android:layout_height="0.0dip"
  29. android:gravity="center_vertical"
  30. android:singleLine="true"
  31. android:ellipsize="end"
  32. android:layout_weight="1"/>
  33. </LinearLayout>
  34. </LinearLayout>

适配器弄好了,ExpandableListView就用系统的,现在只剩下显示的问题啦

先来几张效果图:



主Activity如下:

[java] view plain copy
  1. packagecom.xyz.expande;
  2. importjava.util.ArrayList;
  3. importjava.util.List;
  4. importandroid.app.Activity;
  5. importandroid.app.AlertDialog;
  6. importandroid.content.DialogInterface;
  7. importandroid.content.DialogInterface.OnClickListener;
  8. importandroid.os.Bundle;
  9. importandroid.view.View;
  10. importandroid.view.ViewGroup.LayoutParams;
  11. importandroid.widget.ExpandableListView;
  12. importandroid.widget.ExpandableListView.OnChildClickListener;
  13. publicclassHomeActivityextendsActivityimplementsOnChildClickListener{
  14. privateExpandableListViewmListView=null;
  15. privateExpandeAdaptermAdapter=null;
  16. privateList<List<Item>>mData=newArrayList<List<Item>>();
  17. privateint[]mGroupArrays=newint[]{
  18. R.array.tianlongbabu,
  19. R.array.shediaoyingxiongzhuan,
  20. R.array.shendiaoxialv};
  21. privateint[]mDetailIds=newint[]{
  22. R.array.tianlongbabu_detail,
  23. R.array.shediaoyingxiongzhuan_detail,
  24. R.array.shendiaoxialv_detail};
  25. privateint[][]mImageIds=newint[][]{
  26. {R.drawable.img_00,
  27. R.drawable.img_01,
  28. R.drawable.img_02},
  29. {R.drawable.img_10,
  30. R.drawable.img_11,
  31. R.drawable.img_12,
  32. R.drawable.img_13,
  33. R.drawable.img_14,
  34. R.drawable.img_15,
  35. R.drawable.img_16},
  36. {R.drawable.img_20,
  37. R.drawable.img_21}};
  38. /**Calledwhentheactivityisfirstcreated.*/
  39. @Override
  40. publicvoidonCreate(BundlesavedInstanceState){
  41. super.onCreate(savedInstanceState);
  42. initData();
  43. mListView=newExpandableListView(this);
  44. mListView.setLayoutParams(newLayoutParams(LayoutParams.FILL_PARENT,
  45. LayoutParams.FILL_PARENT));
  46. setContentView(mListView);
  47. mListView.setGroupIndicator(getResources().getDrawable(
  48. R.drawable.expander_floder));
  49. mAdapter=newExpandeAdapter(this,mData);
  50. mListView.setAdapter(mAdapter);
  51. mListView.setOnChildClickListener(this);
  52. }
  53. <spanstyle="color:#ff0000;">/*
  54. *ChildView设置布局很可能onChildClick进不来,要在ChildViewlayout里加上
  55. *android:descendantFocusability="blocksDescendants",
  56. *还有isChildSelectable里返回true
  57. */
  58. </span>@Override
  59. publicbooleanonChildClick(ExpandableListViewparent,Viewv,
  60. intgroupPosition,intchildPosition,longid){
  61. //TODOAuto-generatedmethodstub
  62. Itemitem=mAdapter.getChild(groupPosition,childPosition);
  63. newAlertDialog.Builder(this)
  64. .setTitle(item.getName())
  65. .setMessage(item.getDetail())
  66. .setIcon(android.R.drawable.ic_menu_more)
  67. .setNegativeButton(android.R.string.cancel,
  68. newOnClickListener(){
  69. @Override
  70. publicvoidonClick(DialogInterfacedialog,
  71. intwhich){
  72. //TODOAuto-generatedmethodstub
  73. }
  74. }).create().show();
  75. returntrue;
  76. }
  77. privatevoidinitData(){
  78. for(inti=0;i<mGroupArrays.length;i++){
  79. List<Item>list=newArrayList<Item>();
  80. String[]childs=getStringArray(mGroupArrays[i]);
  81. String[]details=getStringArray(mDetailIds[i]);
  82. for(intj=0;j<childs.length;j++){
  83. Itemitem=newItem(mImageIds[i][j],childs[j],details[j]);
  84. list.add(item);
  85. }
  86. mData.add(list);
  87. }
  88. }
  89. privateString[]getStringArray(intresId){
  90. returngetResources().getStringArray(resId);
  91. }
  92. }

写这个demo的时候,想实现ChildView的点击事件,实现接口onChildClick,发现不进来,很尴尬。。。最后还是在网上找到答案了,第一,在适配器里isChildSelectable 必须返回true,第二,ChildView布局child_item_layout.xml最外层的layout设置个属性:

[java] view plain copy
  1. <spanstyle="FONT-SIZE:14px"><spanxmlns="http://www.w3.org/1999/xhtml"><spanxmlns="http://www.w3.org/1999/xhtml"><spanxmlns="http://www.w3.org/1999/xhtml"><spanxmlns="http://www.w3.org/1999/xhtml">android:descendantFocusability="blocksDescendants"</span></span></span></span></span>
上面已标示红色的啦。

细心的同学会发现 Item 是啥?也贴出来吧

[java] view plain copy
  1. packagecom.xyz.expande;
  2. publicclassItem{
  3. privateintresId;
  4. privateStringname;
  5. privateStringdetail;
  6. publicItem(intresId,Stringname,Stringdetail){
  7. this.resId=resId;
  8. this.name=name;
  9. this.detail=detail;
  10. }
  11. publicvoidsetImageId(intresId){
  12. this.resId=resId;
  13. }
  14. publicintgetImageId(){
  15. returnresId;
  16. }
  17. publicvoidsetName(Stringname){
  18. this.name=name;
  19. }
  20. publicStringgetName(){
  21. returnname;
  22. }
  23. publicvoidsetDetail(Stringdetail){
  24. this.detail=detail;
  25. }
  26. publicStringgetDetail(){
  27. returndetail;
  28. }
  29. publicStringtoString(){
  30. return"Item["+resId+","+name+","+detail+"]";
  31. }
  32. }
。。。这不是面向对象程序设计(OOP)类及类的实现最简单的例子么。

有不对的地方请指正,互相学习!(ChildView左边的图片处理成圆角:请看函数getRoundCornerDrawable:具体细节请看:Android --- 图片的特效处理

免分下载源码路径:http://download.csdn.net/detail/zhouyuanjing/4843520

~~完~~

更多相关文章

  1. 室内定位导航系统设计实现指南
  2. [Android]Android(安卓)FTP server based on Apache FTPServer
  3. 关于android读取用户号码,手机串号,SIM卡序列号
  4. Xposed框架之函数Hook学习
  5. 自定义实现简单的Android颜色选择器(附带源码)
  6. Android调用WebService之服务端实现(一)
  7. Android中activity切换动画的两种实现(附种17种动画效果)
  8. Android(安卓)API Demos学习(1) - Hello World
  9. 浅谈Java中Collections.sort对List排序的两种方法

随机推荐

  1. flutter [!] Android toolchain - develo
  2. Android之开源中国客户端源码分析(二)
  3. 自定义对话框Dialog
  4. Layout1.3
  5. android manifest.xml
  6. Android 5.1 SDK下载与配置
  7. android图片缩放平移
  8. Android 全退出
  9. Android录音应用
  10. 时钟控件AnalogClock和DigitalClock