首页 > 代码库 > 使用ExpandableListView做一个类似QQ列表效果图

使用ExpandableListView做一个类似QQ列表效果图

分组列表视图(ExpandableListView)

和ListView不同的是它是一个两级的滚动列表视图,每一个组可以展开,显示一些子项,类似于
QQ列表,这些项目来至于ExpandableListAdapter的子类,也就是说,要实现向里面添加项目,必
须写一个子类实现ExpandableListAdapter的接口或者使用系统为我们实现在子类

   常用属性   

    1. android:childDivider 指定各组内子类表项之间的分隔条,

    2. android:childIndicator 显示在子列表旁边的Drawable对象

    3. android:childIndicatorLeft 子列表项指示符的左边约束位置

    4. android:childIndicatorRight 子列表项指示符的右边约束位置

    5. android:groupIndicator 显示在组列表旁边的Drawable对象

    6. android:indicatorLeft 组列表项指示器的左边约束位置

    7. android:indicatorRight 组列表项指示器的右边约束位置

一般适用于ExpandableListView的Adapter都要继承BaseExpandableListAdapter这个类,
并且必须重载getGroupView和getChildView这两个最为重要的方法。
当扩展BaseExpandableListAdapter时,要实现全部方法,关键是实现其中的四个方法。

 

1、首相activity_main.xml布局搭建

技术分享
 1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 2     android:layout_width="match_parent" 3     android:layout_height="match_parent"> 4  5     <ExpandableListView 6         android:layout_width="wrap_content" 7         android:layout_height="wrap_content" 8         android:id="@+id/elv"/> 9 10 </RelativeLayout>
activity_main.xml

 

2、然后是搭建QQ分组的布局

技术分享
 1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 2     android:layout_width="match_parent" 3     android:layout_height="match_parent" 4     android:orientation="vertical" > 5  6     <TextView 7         android:id="@+id/groupName" 8         android:layout_width="wrap_content" 9         android:layout_height="wrap_content"10         android:textSize="20sp"11         android:text="分组名称" />12 13     <TextView14         android:id="@+id/groupOnline"15         android:layout_alignParentRight="true"16         android:layout_width="wrap_content"17         android:layout_height="wrap_content"18         android:text="0/8" />19 20 </RelativeLayout>
item_group.xml

 

3、再搭建分组中各选项的布局(QQ联系人,包括头像,昵称,签名)

   这里由于引用了外部的自定义的控件,所以这里包名加类名

技术分享
 1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 2     android:layout_width="match_parent" 3     android:layout_height="match_parent" 4     android:layout_gravity="center_vertical" 5     android:orientation="horizontal" > 6  7     <com.test.lesson7_expandablelistview.CircleImageView 8         android:id="@+id/img" 9         android:layout_width="80dp"10         android:layout_height="80dp"11         android:src="@drawable/ic_launcher" />12 13     <LinearLayout14         android:layout_width="match_parent"15         android:layout_height="wrap_content"16         android:layout_marginLeft="10dp"17         android:orientation="vertical" >18 19         <TextView20             android:id="@+id/nickName"21             android:layout_width="match_parent"22             android:layout_height="wrap_content"23             android:text="昵称"24             android:textSize="18sp" />25 26         <LinearLayout27             android:layout_width="match_parent"28             android:layout_height="wrap_content"29             android:layout_marginTop="10dp"30             android:orientation="horizontal" >31 32             <TextView33                 android:id="@+id/online"34                 android:layout_width="wrap_content"35                 android:layout_height="wrap_content"36                 android:text="[在线]" />37 38             <TextView39                 android:id="@+id/sign"40                 android:layout_width="wrap_content"41                 android:layout_height="wrap_content"42                 android:layout_marginLeft="10dp"43                 android:text="我要飞的更高~" />44         </LinearLayout>45     </LinearLayout>46 47 </LinearLayout>
item_child.xml

 

 

4、圆角图片形状

  在res/values中建circle_attr.xml

1 <resources>2 3     <declare-styleable name="CircularImage">4         <attr name="border_width" format="dimension" />5         <attr name="border_color" format="color" />6     </declare-styleable>7 8 </resources>

5、然后新建一个CircleImageView继承ImageView

  此处自定义控件是在GitHub上下载

技术分享
 1 public class CircleImageView extends ImageView { 2     private static final Xfermode MASK_XFERMODE; 3     private Bitmap mask; 4     private Paint paint; 5     private int mBorderWidth = 10; 6     private int mBorderColor = Color.parseColor("#f2f2f2"); 7     private boolean useDefaultStyle = false; 8  9     static {10         PorterDuff.Mode localMode = PorterDuff.Mode.DST_IN;11         MASK_XFERMODE = new PorterDuffXfermode(localMode);12     }13 14     public CircleImageView(Context context) {15         super(context);16     }17 18     public CircleImageView(Context context, AttributeSet attrs) {19         this(context, attrs, 0);20     }21 22     public CircleImageView(Context context, AttributeSet attrs, int defStyle) {23         super(context, attrs, defStyle);24         TypedArray a = context.obtainStyledAttributes(attrs,25                 R.styleable.CircularImage);26         mBorderColor = a.getColor(R.styleable.CircularImage_border_color,27                 mBorderColor);28         final int def = (int) (2 * context.getResources().getDisplayMetrics().density + 0.5f);29         mBorderWidth = a.getDimensionPixelOffset(30                 R.styleable.CircularImage_border_width, def);31         a.recycle();32     }33 34     private void useDefaultStyle(boolean useDefaultStyle) {35         this.useDefaultStyle = useDefaultStyle;36     }37 38     @Override39     protected void onDraw(Canvas canvas) {40         if (useDefaultStyle) {41             super.onDraw(canvas);42             return;43         }44         final Drawable localDraw = getDrawable();45         if (localDraw == null) {46             return;47         }48         if (localDraw instanceof NinePatchDrawable) {49             return;50         }51         if (this.paint == null) {52             final Paint localPaint = new Paint();53             localPaint.setFilterBitmap(false);54             localPaint.setAntiAlias(true);55             localPaint.setXfermode(MASK_XFERMODE);56             this.paint = localPaint;57         }58         final int width = getWidth();59         final int height = getHeight();60         int layer = canvas.saveLayer(0.0F, 0.0F, width, height, null, 31);61         localDraw.setBounds(0, 0, width, height);62         localDraw.draw(canvas);63         if ((this.mask == null) || (this.mask.isRecycled())) {64             this.mask = createOvalBitmap(width, height);65         }66         canvas.drawBitmap(this.mask, 0.0F, 0.0F, this.paint);67         canvas.restoreToCount(layer);68         drawBorder(canvas, width, height);69     }70 71     private void drawBorder(Canvas canvas, final int width, final int height) {72         if (mBorderWidth == 0) {73             return;74         }75         final Paint mBorderPaint = new Paint();76         mBorderPaint.setStyle(Paint.Style.STROKE);77         mBorderPaint.setAntiAlias(true);78         mBorderPaint.setColor(mBorderColor);79         mBorderPaint.setStrokeWidth(mBorderWidth);80         canvas.drawCircle(width / 2, height / 2, (width - mBorderWidth) / 2,81                 mBorderPaint);82         canvas = null;83     }84 85     public Bitmap createOvalBitmap(final int width, final int height) {86         Bitmap.Config localConfig = Bitmap.Config.ARGB_8888;87         Bitmap localBitmap = Bitmap.createBitmap(width, height, localConfig);88         Canvas localCanvas = new Canvas(localBitmap);89         Paint localPaint = new Paint();90         final int padding = (mBorderWidth - 3) > 0 ? mBorderWidth - 3 : 1;91 92         RectF localRectF = new RectF(padding, padding, width - padding, height93                 - padding);94         localCanvas.drawOval(localRectF, localPaint);95 96         return localBitmap;97     }98 99 }
CircleImageView

 

6、创建Group类

技术分享
 1 public class Group { 2     //分组名 3     public String groupName; 4     //有很多User 5     public List<User> list; 6      7     public Group(String groupName){ 8         this.groupName = groupName; 9         list = new ArrayList<User>();10     }11     //添加User12     public void addUser(User user){13         list.add(user);14     }15     16     //获取某个分组中User的数量17     public int getChildCount() {18         return list.size();19     }20     //获取某个分组中User在线的数量21     public int getOnlineCount(){22         int sum = 0;23         for (User user : list) {24             if(user.isOnline()){25                 sum++;26             }27         }28         return sum;29     }30     //获取分组中某个孩子31     public User getChild(int childPosition) {32         return list.get(childPosition);33     }34     35     36 }
Group.java

 

7、创建User类

技术分享
 1 public class User { 2     private int imgId; 3     private String nickName; 4     private boolean isOnline; 5     private String sign; 6      7      8     public User() { 9         super();10     }11     public User(int imgId, String nickName, boolean isOnline, String sign) {12         super();13         this.imgId = imgId;14         this.nickName = nickName;15         this.isOnline = isOnline;16         this.sign = sign;17     }18     19     public int getImgId() {20         return imgId;21     }22     public void setImgId(int imgId) {23         this.imgId = imgId;24     }25     public String getNickName() {26         return nickName;27     }28     public void setNickName(String nickName) {29         this.nickName = nickName;30     }31     public boolean isOnline() {32         return isOnline;33     }34     public void setOnline(boolean isOnline) {35         this.isOnline = isOnline;36     }37     public String getSign() {38         return sign;39     }40     public void setSign(String sign) {41         this.sign = sign;42     }43     44     45     46     47 }
User

 

8、设置适配器

技术分享
  1 public class GroupAdapter extends BaseExpandableListAdapter{  2   3     Context context;  4     List<Group> list;  5       6     public GroupAdapter(Context context, List<Group> list) {  7         this.context = context;  8         this.list = list;  9     } 10      11     @Override 12     public View getGroupView(int groupPosition, boolean isExpanded, 13             View convertView, ViewGroup parent) { 14         GroupHolder holder; 15         if(convertView == null){ 16             convertView = View.inflate(context, R.layout.item_grouplayout, null); 17             holder = new GroupHolder(convertView); 18             convertView.setTag(holder); 19         }else{ 20             holder = (GroupHolder) convertView.getTag(); 21         } 22         //设置数据 23         Group group = getGroup(groupPosition); 24         holder.groupName.setText(group.groupName); 25         holder.groupOnline.setText(group.getOnlineCount()+"/"+getChildrenCount(groupPosition)); 26          27         return convertView; 28     } 29  30     @Override 31     public View getChildView(int groupPosition, int childPosition, 32             boolean isLastChild, View convertView, ViewGroup parent) { 33         ChildHolder holder; 34         if(convertView == null){ 35             convertView = View.inflate(context, R.layout.item_childlayout, null); 36             holder = new ChildHolder(convertView); 37             convertView.setTag(holder); 38         }else{ 39             holder = (ChildHolder) convertView.getTag(); 40         } 41         //设置数据 42         User user = getGroup(groupPosition).getChild(childPosition); 43         holder.img.setImageResource(user.getImgId()); 44         holder.nickName.setText(user.getNickName()); 45         holder.online.setText(user.isOnline()?"[在线]":"[离线]"); 46         holder.sign.setText(user.getSign()); 47          48         return convertView; 49          50     } 51      52     class GroupHolder{ 53         TextView groupName; 54         TextView groupOnline; 55          56         public GroupHolder(View convertView){ 57             groupName = (TextView) convertView.findViewById(R.id.groupName); 58             groupOnline = (TextView) convertView.findViewById(R.id.groupOnline); 59              60         } 61     } 62     class ChildHolder{ 63         ImageView img; 64         TextView nickName; 65         TextView online; 66         TextView sign; 67          68         public ChildHolder(View convertView){ 69             img = (ImageView) convertView.findViewById(R.id.img); 70             nickName = (TextView) convertView.findViewById(R.id.nickName); 71             online = (TextView) convertView.findViewById(R.id.online); 72             sign = (TextView) convertView.findViewById(R.id.sign); 73              74         } 75          76     } 77      78     @Override 79     public int getGroupCount() { 80         return list.size(); 81     } 82  83     @Override 84     public int getChildrenCount(int groupPosition) { 85         return list.get(groupPosition).getChildCount(); 86     } 87  88     @Override 89     public Group getGroup(int groupPosition) { 90         return list.get(groupPosition); 91     } 92  93     @Override 94     public User getChild(int groupPosition, int childPosition) { 95         return list.get(groupPosition).getChild(childPosition); 96     } 97  98     @Override 99     public long getGroupId(int groupPosition) {100         return groupPosition;101     }102 103     @Override104     public long getChildId(int groupPosition, int childPosition) {105         return childPosition;106     }107 108     @Override109     public boolean hasStableIds() {110         return true;111     }112 113     @Override114     public boolean isChildSelectable(int groupPosition, int childPosition) {115         return true;116     }117 118 }
GroupAdapter

 

9、MainActivity.java中将所有组件找到,初始化数据源,并给ListView设置适配器

技术分享
 1 public class MainActivity extends Activity { 2  3     ExpandableListView elv; 4     private List<Group> list = new ArrayList<Group>(); 5     int[] img = new int[6]; 6      7     @Override 8     protected void onCreate(Bundle savedInstanceState) { 9         super.onCreate(savedInstanceState);10         setContentView(R.layout.activity_main);11         initData();12         elv = (ExpandableListView) findViewById(R.id.elv);13         GroupAdapter adapter = new GroupAdapter(getBaseContext(), list);14         elv.setAdapter(adapter);15         16     }17 18     private void initData() {19         for (int i = 0; i < img.length; i++) {20             try {21                 img[i] = R.drawable.class.getField("img0"+(i+1)).getInt(null);22             } catch (Exception e) {23                 e.printStackTrace();24             }25         }26         27         Group group1 = new Group("贵圈好乱");28         group1.addUser(new User(img[0], "张翰", true, "我爱娜扎!"));29         group1.addUser(new User(img[1], "郑爽", false, "妈蛋,要么瘦,要么死!"));30         group1.addUser(new User(img[2], "胡彦斌", true, "其实我只是长得抽象了"));31         group1.addUser(new User(img[5], "撒贝宁", true, "子怡当年没选择我是个美丽的错误"));32         group1.addUser(new User(img[3], "杨幂", false, "其实我跟恺威已经离婚了,现在跟李易峰在一起,就酱~"));33         34         Group group2 = new Group("超星星");35         group2.addUser(new User(img[4], "林志炫", true, "其实我的小肚子都是唱歌导致的,哈哈哈"));36         37         list.add(group1);38         list.add(group2);39         40     }41     42     43 }
MainActivity.java

 

 

运行效果有点渣渣。请忽略:

技术分享

 

使用ExpandableListView做一个类似QQ列表效果图