android 实现QQ好友列表(扩展listview:ExpandableListView)

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

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

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

[java] view plain copy
  1. <span xmlns="http://www.w3.org/1999/xhtml">package com.xyz.expande;  
  2.   
  3. import java.util.List;  
  4.   
  5. import android.app.AlertDialog;  
  6. import android.content.Context;  
  7. import android.graphics.Bitmap;  
  8. import android.graphics.Bitmap.Config;  
  9. import android.graphics.Canvas;  
  10. import android.graphics.Paint;  
  11. import android.graphics.PixelFormat;  
  12. import android.graphics.PorterDuff.Mode;  
  13. import android.graphics.PorterDuffXfermode;  
  14. import android.graphics.Rect;  
  15. import android.graphics.RectF;  
  16. import android.graphics.drawable.BitmapDrawable;  
  17. import android.graphics.drawable.Drawable;  
  18. import android.util.Log;  
  19. import android.view.LayoutInflater;  
  20. import android.view.View;  
  21. import android.view.ViewGroup;  
  22. import android.widget.BaseExpandableListAdapter;  
  23. import android.widget.ImageView;  
  24. import android.widget.TextView;  
  25.   
  26. public class ExpandeAdapter extends BaseExpandableListAdapter {  
  27.   
  28.     private Context mContext;  
  29.     private LayoutInflater mInflater = null;  
  30.     private String[] mGroupStrings = null;  
  31.     private List<List<Item>> mData = null;  
  32.   
  33.     public ExpandeAdapter(Context ctx, List<List<Item>> list) {  
  34.         mContext = ctx;  
  35.         mInflater = (LayoutInflater) mContext  
  36.                 .getSystemService(Context.LAYOUT_INFLATER_SERVICE);  
  37.         mGroupStrings = mContext.getResources().getStringArray(R.array.groups);  
  38.         mData = list;  
  39.     }  
  40.   
  41.     public void setData(List<List<Item>> list) {  
  42.         mData = list;  
  43.     }  
  44.   
  45.     @Override  
  46.     public int getGroupCount() {  
  47.         // TODO Auto-generated method stub  
  48.         return mData.size();  
  49.     }  
  50.   
  51.     @Override  
  52.     public int getChildrenCount(int groupPosition) {  
  53.         // TODO Auto-generated method stub  
  54.         return mData.get(groupPosition).size();  
  55.     }  
  56.   
  57.     @Override  
  58.     public List<Item> getGroup(int groupPosition) {  
  59.         // TODO Auto-generated method stub  
  60.         return mData.get(groupPosition);  
  61.     }  
  62.   
  63.     @Override  
  64.     public Item getChild(int groupPosition, int childPosition) {  
  65.         // TODO Auto-generated method stub  
  66.         return mData.get(groupPosition).get(childPosition);  
  67.     }  
  68.   
  69.     @Override  
  70.     public long getGroupId(int groupPosition) {  
  71.         // TODO Auto-generated method stub  
  72.         return groupPosition;  
  73.     }  
  74.   
  75.     @Override  
  76.     public long getChildId(int groupPosition, int childPosition) {  
  77.         // TODO Auto-generated method stub  
  78.         return childPosition;  
  79.     }  
  80.   
  81.     @Override  
  82.     public boolean hasStableIds() {  
  83.         // TODO Auto-generated method stub  
  84.         return false;  
  85.     }  
  86.   
  87.     @Override  
  88.     public View getGroupView(int groupPosition, boolean isExpanded,  
  89.             View convertView, ViewGroup parent) {  
  90.         // TODO Auto-generated method stub  
  91.         if (convertView == null) {  
  92.             convertView = mInflater.inflate(R.layout.group_item_layout, null);  
  93.         }  
  94.         GroupViewHolder holder = new GroupViewHolder();  
  95.         holder.mGroupName = (TextView) convertView  
  96.                 .findViewById(R.id.group_name);  
  97.         holder.mGroupName.setText(mGroupStrings[groupPosition]);  
  98.         holder.mGroupCount = (TextView) convertView  
  99.                 .findViewById(R.id.group_count);  
  100.         holder.mGroupCount.setText("[" + mData.get(groupPosition).size() + "]");  
  101.         return convertView;  
  102.     }  
  103.   
  104.     @Override  
  105.     public View getChildView(int groupPosition, int childPosition,  
  106.             boolean isLastChild, View convertView, ViewGroup parent) {  
  107.         // TODO Auto-generated method stub  
  108.         if (convertView == null) {  
  109.             convertView = mInflater.inflate(R.layout.child_item_layout, null);  
  110.         }  
  111.         ChildViewHolder holder = new ChildViewHolder();  
  112.         holder.mIcon = (ImageView) convertView.findViewById(R.id.img);  
  113.         holder.mIcon.setBackgroundDrawable(getRoundCornerDrawable(  
  114.                 getChild(groupPosition, childPosition).getImageId(), 10));  
  115.         holder.mChildName = (TextView) convertView.findViewById(R.id.item_name);  
  116.         holder.mChildName.setText(getChild(groupPosition, childPosition)  
  117.                 .getName());  
  118.         holder.mDetail = (TextView) convertView.findViewById(R.id.item_detail);  
  119.         holder.mDetail.setText(getChild(groupPosition, childPosition)  
  120.                 .getDetail());  
  121.         return convertView;  
  122.     }  
  123.   
  124.     @Override  
  125.     public boolean isChildSelectable(int groupPosition, int childPosition) {  
  126.         // TODO Auto-generated method stub  
  127.         /* 很重要:实现ChildView点击事件,必须返回true */  
  128.         return true;  
  129.     }  
  130.   
  131.     private Drawable getRoundCornerDrawable(int resId, float roundPX /* 圆角的半径 */) {  
  132.         Drawable drawable = mContext.getResources().getDrawable(resId);  
  133.         int w = mContext.getResources().getDimensionPixelSize(R.dimen.image_width);  
  134.         int h = w;  
  135.   
  136.         Bitmap bitmap = Bitmap  
  137.                 .createBitmap(w,h,  
  138.                         drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888  
  139.                                 : Bitmap.Config.RGB_565);  
  140.         Canvas canvas = new Canvas(bitmap);  
  141.         drawable.setBounds(00, w, h);  
  142.         drawable.draw(canvas);  
  143.   
  144.         int width = bitmap.getWidth();  
  145.         int height = bitmap.getHeight();  
  146.         Bitmap retBmp = Bitmap.createBitmap(width, height, Config.ARGB_8888);  
  147.         Canvas can = new Canvas(retBmp);  
  148.   
  149.         final int color = 0xff424242;  
  150.         final Paint paint = new Paint();  
  151.         final Rect rect = new Rect(00, width, height);  
  152.         final RectF rectF = new RectF(rect);  
  153.   
  154.         paint.setColor(color);  
  155.         paint.setAntiAlias(true);  
  156.         can.drawARGB(0000);  
  157.         can.drawRoundRect(rectF, roundPX, roundPX, paint);  
  158.   
  159.         paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));  
  160.         can.drawBitmap(bitmap, rect, rect, paint);  
  161.         return new BitmapDrawable(retBmp);  
  162.     }  
  163.   
  164.     private class GroupViewHolder {  
  165.         TextView mGroupName;  
  166.         TextView mGroupCount;  
  167.     }  
  168.   
  169.     private class ChildViewHolder {  
  170.         ImageView mIcon;  
  171.         TextView mChildName;  
  172.         TextView mDetail;  
  173.     }  
  174.   
  175. }  
  176. </span>  
        里面用到的有两个布局,GroupView(ChildViewt没展开的情况)如图:  

布局group_item_layout.xml如下:

[html] view plain copy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns: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.   
  7.     <TextView  
  8.         android:id="@+id/group_name"  
  9.         android:layout_width="wrap_content"  
  10.         android:layout_height="?android:attr/listPreferredItemHeight"  
  11.         android:textAppearance="?android:attr/textAppearanceMedium"  
  12.         android:layout_marginLeft="35dip"  
  13.         android:gravity="center_vertical"  
  14.         android:singleLine="true" />  
  15.   
  16.     <TextView  
  17.         android:id="@+id/group_count"  
  18.         android:layout_width="wrap_content"  
  19.         android:layout_height="?android:attr/listPreferredItemHeight"  
  20.         android:textAppearance="?android:attr/textAppearanceMedium"  
  21.         android:layout_marginLeft="5dip"  
  22.         android:gravity="center_vertical"  
  23.         android:singleLine="true"/>  
  24.   
  25. </LinearLayout>  

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


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

[html] view plain copy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns: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.     <span style="color:#ff0000;">android:descendantFocusability="blocksDescendants"  
  7. </span>    android:orientation="horizontal" >  
  8.   
  9.     <ImageView  
  10.         android:id="@+id/img"  
  11.         android:layout_width="@dimen/image_width"  
  12.         android:layout_height="@dimen/image_width"  
  13.         android:layout_marginLeft="2dip"  
  14.         android:layout_marginRight="10dip"  
  15.         android:layout_gravity="center_vertical" />  
  16.   
  17.     <LinearLayout  
  18.         android:layout_width="wrap_content"  
  19.         android:layout_height="match_parent"  
  20.         android:orientation="vertical" >  
  21.   
  22.         <TextView  
  23.             android:id="@+id/item_name"  
  24.             android:layout_width="wrap_content"  
  25.             android:layout_height="0.0dip"  
  26.             android:gravity="center_vertical"  
  27.             android:layout_weight="1" />  
  28.   
  29.         <TextView  
  30.             android:id="@+id/item_detail"  
  31.             android:layout_width="wrap_content"  
  32.             android:layout_height="0.0dip"  
  33.             android:gravity="center_vertical"  
  34.             android:singleLine="true"  
  35.             android:ellipsize="end"  
  36.             android:layout_weight="1" />  
  37.           
  38.     </LinearLayout>  
  39.   
  40. </LinearLayout>  

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

        先来几张效果图:

android 实现QQ好友列表(扩展listview:ExpandableListView)_第1张图片

android 实现QQ好友列表(扩展listview:ExpandableListView)_第2张图片

android 实现QQ好友列表(扩展listview:ExpandableListView)_第3张图片


主Activity如下:

[java] view plain copy
  1. package com.xyz.expande;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.List;  
  5.   
  6. import android.app.Activity;  
  7. import android.app.AlertDialog;  
  8. import android.content.DialogInterface;  
  9. import android.content.DialogInterface.OnClickListener;  
  10. import android.os.Bundle;  
  11. import android.view.View;  
  12. import android.view.ViewGroup.LayoutParams;  
  13. import android.widget.ExpandableListView;  
  14. import android.widget.ExpandableListView.OnChildClickListener;  
  15.   
  16. public class HomeActivity extends Activity implements OnChildClickListener {  
  17.   
  18.     private ExpandableListView mListView = null;  
  19.     private ExpandeAdapter mAdapter = null;  
  20.     private List<List<Item>> mData = new ArrayList<List<Item>>();  
  21.   
  22.     private int[] mGroupArrays = new int[] {   
  23.             R.array.tianlongbabu,  
  24.             R.array.shediaoyingxiongzhuan,   
  25.             R.array.shendiaoxialv };  
  26.   
  27.     private int[] mDetailIds = new int[] {   
  28.             R.array.tianlongbabu_detail,  
  29.             R.array.shediaoyingxiongzhuan_detail,   
  30.             R.array.shendiaoxialv_detail };  
  31.   
  32.     private int[][] mImageIds = new int[][] {  
  33.             { R.drawable.img_00,   
  34.               R.drawable.img_01,   
  35.               R.drawable.img_02 },  
  36.             { R.drawable.img_10,   
  37.               R.drawable.img_11,   
  38.               R.drawable.img_12,  
  39.               R.drawable.img_13,   
  40.               R.drawable.img_14,   
  41.               R.drawable.img_15,  
  42.               R.drawable.img_16 },  
  43.             { R.drawable.img_20,  
  44.               R.drawable.img_21 } };  
  45.   
  46.     /** Called when the activity is first created. */  
  47.     @Override  
  48.     public void onCreate(Bundle savedInstanceState) {  
  49.         super.onCreate(savedInstanceState);  
  50.         initData();  
  51.         mListView = new ExpandableListView(this);  
  52.         mListView.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,  
  53.                 LayoutParams.FILL_PARENT));  
  54.         setContentView(mListView);  
  55.           
  56.         mListView.setGroupIndicator(getResources().getDrawable(  
  57.                 R.drawable.expander_floder));  
  58.         mAdapter = new ExpandeAdapter(this, mData);  
  59.         mListView.setAdapter(mAdapter);  
  60.         mListView.setOnChildClickListener(this);  
  61.     }  
  62.   
  63.     <span style="color:#ff0000;">/* 
  64.      * ChildView 设置 布局很可能onChildClick进不来,要在 ChildView layout 里加上 
  65.      * android:descendantFocusability="blocksDescendants", 
  66.      * 还有isChildSelectable里返回true 
  67.      */  
  68. </span>    @Override  
  69.     public boolean onChildClick(ExpandableListView parent, View v,  
  70.             int groupPosition, int childPosition, long id) {  
  71.         // TODO Auto-generated method stub  
  72.         Item item = mAdapter.getChild(groupPosition, childPosition);  
  73.         new AlertDialog.Builder(this)  
  74.                 .setTitle(item.getName())  
  75.                 .setMessage(item.getDetail())  
  76.                 .setIcon(android.R.drawable.ic_menu_more)  
  77.                 .setNegativeButton(android.R.string.cancel,  
  78.                         new OnClickListener() {  
  79.                             @Override  
  80.                             public void onClick(DialogInterface dialog,  
  81.                                     int which) {  
  82.                                 // TODO Auto-generated method stub  
  83.   
  84.                             }  
  85.                         }).create().show();  
  86.         return true;  
  87.     }  
  88.   
  89.     private void initData() {  
  90.         for (int i = 0; i < mGroupArrays.length; i++) {  
  91.             List<Item> list = new ArrayList<Item>();  
  92.             String[] childs = getStringArray(mGroupArrays[i]);  
  93.             String[] details = getStringArray(mDetailIds[i]);  
  94.             for (int j = 0; j < childs.length; j++) {  
  95.                 Item item = new Item(mImageIds[i][j], childs[j], details[j]);  
  96.                 list.add(item);  
  97.             }  
  98.             mData.add(list);  
  99.         }  
  100.     }  
  101.   
  102.     private String[] getStringArray(int resId) {  
  103.         return getResources().getStringArray(resId);  
  104.     }  
  105.   
  106. }  

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

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

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

[java] view plain copy
  1. package com.xyz.expande;  
  2.   
  3. public class Item {  
  4.       
  5.     private int resId;  
  6.     private String name;  
  7.     private String detail;  
  8.       
  9.     public Item(int resId, String name, String detail) {  
  10.         this.resId  = resId;  
  11.         this.name   = name;  
  12.         this.detail = detail;  
  13.     }  
  14.       
  15.     public void setImageId(int resId) {  
  16.         this.resId  = resId;  
  17.     }  
  18.       
  19.     public int getImageId() {  
  20.         return resId;  
  21.     }  
  22.       
  23.     public void setName(String name) {  
  24.         this.name   = name;  
  25.     }  
  26.       
  27.     public String getName() {  
  28.         return name;  
  29.     }  
  30.       
  31.     public void setDetail(String detail) {  
  32.         this.detail = detail;  
  33.     }  
  34.       
  35.     public String getDetail() {  
  36.         return detail;  
  37.     }  
  38.       
  39.     public String toString() {  
  40.         return "Item[" + resId + ", " + name + ", " + detail + "]";  
  41.     }  
  42.   
  43. }  
    。。。这不是面向对象程序设计(OOP)类及类的实现最简单的例子么。

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

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

    ~~完~~

你可能感兴趣的:(android)