分组列表视图(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
运行效果有点渣渣。请忽略: