使用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     <TextView
14         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     <LinearLayout
14         android:layout_width="match_parent"
15         android:layout_height="wrap_content"
16         android:layout_marginLeft="10dp"
17         android:orientation="vertical" >
18
19         <TextView
20             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         <LinearLayout
27             android:layout_width="match_parent"
28             android:layout_height="wrap_content"
29             android:layout_marginTop="10dp"
30             android:orientation="horizontal" >
31
32             <TextView
33                 android:id="@+id/online"
34                 android:layout_width="wrap_content"
35                 android:layout_height="wrap_content"
36                 android:text="[在线]" />
37
38             <TextView
39                 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     @Override
39     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, height
93                 - 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     //添加User
12     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     @Override
104     public long getChildId(int groupPosition, int childPosition) {
105         return childPosition;
106     }
107
108     @Override
109     public boolean hasStableIds() {
110         return true;
111     }
112
113     @Override
114     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

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

时间: 2024-10-12 17:11:44

使用ExpandableListView做一个类似QQ列表效果图的相关文章

iOS tableViewCell 在cell赋值、网络加载照片位置偏移大小错乱,做一个类似qq列表的tableview

需求: 类似QQ列表的头像加载刷新,判断在线离线状态改变头像,以及彩色头像灰色处理,下载图片+获取在线状态需要连网--再改变头像 问题:由于cell的复用以及下拉刷新数据每次加载10条数据,会出现头像赋值不正确,位置偏移大小不同的变化 原因:由于cell的重复调用,加载数据方法已经赋值方法也在重复的调用,所以头像加载 在线状态判断好后,网络延迟, (个人开始yy:启动时的cell和赋值结束的cell可能不是同一个) 修改:当cell开始调用的时候,给当前的cell赋tag值,加载结束判断是不是自

使用plupload做一个类似qq邮箱附件上传的效果

公司项目中使用的框架是springmvc+hibernate+spring,目前需要做一个类似qq邮箱附件上传的功能,暂时只是上传小类型的附件 处理过程和解决方案都需要添加附件,处理过程和解决方案都可以添加多个附件,也可一个都不添加 以其中一个为例:(文件保存到了数据库中),有关plupload的内容可参考:http://www.360doc.com/content/14/0714/03/552866_394228686.shtml 首先是po package cn.com.plupload.p

第一讲 从头开始做一个web qq 机器人,第一步获取smart qq二维码

新手教程: 前言:最近在看了一下很久很久以前做的qq机器人失效了,最近也在换工作目前还在职,时间很挺宽裕的.就决定从新搞一个web qq机器人 PC的协议解析出来有点费时间以后再做. 准备工作: 编译工具:vs2017 编程语言:C# 或者.net 开始建一个SDK  新建文件 -项目 -选择类库-(WEBQQSDK)-添加一个类 smartqq 第一步,登录了一下Smart QQ,以这个HTTP协议,做机器人交互吧,TX把这个版本的很多功能去掉了,基本的群聊,私聊 收发信息之类还在.(用谷歌浏

做一个类似JQuery获取DOM对象的$()

在dom操作时,有时根据id获取单个对象.有时根据className获取多个对象.平常可能我们用两个函数来实现这两个功能.不过我将它们整合了一下,目前使用情况良好,函数如下: view source print? 01 // 根据selector获取单个或多个元素, 02 // 获取多个元素时,可以指定元素的tag类型和父元素 03 function $(selector, tag, parent) { 04     var ret = []; 05     06     //没有传递selec

做一个类似共享链商家的小程序

当我们想要做一款类似于共享链商家的小城,(微=175-2043*6907)我们该怎么开始?返利分销共享链商家小程序开发 源码下载 共享链依托于微信小程序, 涵盖场景包括电商.零售.教育.医疗.金融等, 其拥有去中心化和分布式账本特点, 实现公平.公正.公开,便捷.安全,高效, 最快实现T+0到账等产品功能: 顾客,使用扫码支付,随机获得消费奖励, 免去在实体店排队等候现金结账的漫长时间: 商户,通过设置让利比率,直接回馈消费者, 免去昂贵广告费用,免找零,零假币,支付即营销. 由于共享链商家是一

做一个类似登录的循环

m=1while m<3: for i in range(3):#循环三次 x = input('x') if int(x)==123: print('welcome'.upper()) exit() else: print('try again'.title()) m+=1 c=input('keep?') if c=='yes': m=1 else: break

详解C# 网络编程系列:实现类似QQ的即时通信程序

引言: 前面专题中介绍了UDP.TCP和P2P编程,并且通过一些小的示例来让大家更好的理解它们的工作原理以及怎样.Net类库去实现它们的.为了让大家更好的理解我们平常中常见的软件QQ的工作原理,所以在本专题中将利用前面专题介绍的知识来实现一个类似QQ的聊天程序.  一.即时通信系统 在我们的生活中经常使用即时通信的软件,我们经常接触到的有:QQ.阿里旺旺.MSN等等.这些都是属于即时通信(Instant Messenger,IM)软件,IM是指所有能够即时发送和接收互联网消息的软件. 在前面专题

[C# 网络编程系列]专题九:实现类似QQ的即时通信程序

转自:http://www.cnblogs.com/zhili/archive/2012/09/23/2666987.html 引言: 前面专题中介绍了UDP.TCP和P2P编程,并且通过一些小的示例来让大家更好的理解它们的工作原理以及怎样.Net类库去实现它们的.为了让大家更好的理解我们平常中常见的软件QQ的工作原理,所以在本专题中将利用前面专题介绍的知识来实现一个类似QQ的聊天程序. 一.即时通信系统 在我们的生活中经常使用即时通信的软件,我们经常接触到的有:QQ.阿里旺旺.MSN等等.这些

做一个Android音乐播放器是遇到的一些困难

最近再做一个安卓的音乐播放器,是实验室里学长派的任务,我是在eclipse上进行开发的,由于没有android的基础,所以做起来困难重重. 首先是布局上的困难 1.layout里的控件属性不熟悉 2.想做一个音乐列表做不出来知道要用Listview控件,网上也找了许多的音乐播放器的代码,但导入项目中总会出错,所以想在这里请教各位 3.除了布局有困难外,实现相关功能也有困难,由于基础不行所以我并不想也做不出网上音乐播放器那么多的功能,我只想要我的播放器有播放,暂停,上一曲,下一曲的效果就行了,这还