首页 > 代码库 > 使用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>
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>
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>
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 }
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 }
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 }
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 }
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 }
运行效果有点渣渣。请忽略:
使用ExpandableListView做一个类似QQ列表效果图