Android ExpandableListView的技巧
前言:
ExpandableListView是可扩展的下拉列表,它的可扩展性在于点击父item可以拉下或收起列表,适用于一些场景的使用,下面介绍的是在Activity中如何使用(如果对ExpandableListView一无所知,建议按照顺序去阅读,遇到问题再看本文)
1、Android中ExpandableListView的使用
网址:http://blog.****.net/gyflyx/article/details/6461242
2、[Android UI设计]ExpandableListView详解
网址:http://www.tuicool.com/articles/JjaMnqf
ExpandableListView是Android中可以实现下拉ListView的一个控件,是ListView的子类。
直接上图,就是这么一功能~
(点击就会展开,再点击就缩回去)
Android自带的布局不是这样的,这个是自定义了Group和Child的布局。
ExpandableListView的使用步骤:
1、在xml中定义一个ExpandableListView
2、在类中定义两个List集合,用于存放Group/Child中的内容,并初始化内容
3、定义ExpandableListView的Adapter,继承BaseExpanableListAdapter
例如:public class MyExpandableAdapter extends BaseExpandableListAdapter
4、最后给定义好的ExpandableView添加上Adapte
activity_expandable_list.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/colorshallowgray"> <ExpandableListView android:id="@+id/ev_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/colorWhite" android:divider="@null" android:groupIndicator="@null" android:cacheColorHint="#00000000" android:listSelector="#00000000" /> </LinearLayout>
adapter_expandlist_group_item.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="70dp" android:gravity="center_vertical" android:paddingLeft="12dp"> <ImageView android:id="@+id/iv_expandlist_group" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@mipmap/ic_arrow_right"/> <TextView android:id="@+id/tv_expandlist_group_name" android:layout_width="wrap_content" android:layout_height="50dp" android:gravity="center_vertical" android:layout_marginLeft="12dp" android:textColor="@color/colorBlack" android:textSize="20sp"/> </LinearLayout>
adapter_expandlist_child_item.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingLeft="16dp"> <com.makeramen.roundedimageview.RoundedImageView android:id="@+id/iv_expandlist_child_avatar" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="40dp" android:layout_height="40dp" android:scaleType="fitCenter" android:src="@mipmap/luxun" app:riv_oval="true"/> <LinearLayout android:layout_width="match_parent" android:layout_height="50dp" android:orientation="vertical" android:paddingLeft="12dp"> <TextView android:id="@+id/tv_expandlist_child_name" android:layout_width="match_parent" android:layout_height="25dp" android:gravity="center_vertical" android:textColor="@color/colorRed" android:textSize="20dp" /> <TextView android:id="@+id/tv_expandlist_child_content" android:layout_width="match_parent" android:layout_height="24dp" android:textColor="@color/colorLightBlack" android:textSize="16dp" /> <ImageView android:id="@+id/iv_expandlist_child_divider" android:layout_width="match_parent" android:layout_height="0.5dp" android:background="@color/colorShallowBlack"/> </LinearLayout> </LinearLayout>
<com.makeramen.roundedimageview.RoundedImageView android:id="@+id/iv_expandlist_child_avatar" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="40dp" android:layout_height="40dp" android:scaleType="fitCenter" android:src="@mipmap/luxun" app:riv_oval="true"/>
圆形头像可参考:http://blog.****.net/heaven_bingwang/article/details/71423146
ExpandableListActivity.java
package com.neon.crm.activity.listview; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.view.Window; import android.widget.ExpandableListView; import android.widget.Toast; import com.neon.crm.R; import com.neon.crm.adapter.ExpandableListAdapter; import java.util.ArrayList; import java.util.List; /** * Created by Administrator on 2017/5/5. * ExpandableListActivity */ public class ExpandableListActivity extends Activity { private ExpandableListView expandableListView; //设置组视图的显示文字 private List<String> group; //组列表 private List<List<String>> child; //子列表 private List<List<Integer>> logou; //子列表 private ExpandableListAdapter adapter;; //数据适配器 @Override protected void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_expandable_list); findViewById(); ininData(); } public void findViewById(){ expandableListView = (ExpandableListView) findViewById(R.id.ev_view); } /** * 初始化组、子列表数据 */ public void ininData(){ group = new ArrayList<String>(); child = new ArrayList<List<String>>(); logou = new ArrayList<List<Integer>>(); addInfo("魏", new String[]{ "夏侯惇", "甄姬", "许褚", "郭嘉", "司马懿", "杨修" }, new Integer[]{ R.mipmap.xiahoudun, R.mipmap.zhenji, R.mipmap.xuchu, R.mipmap.guojia, R.mipmap.simayi, R.mipmap.yangxiu } ) ; addInfo("蜀", new String[]{ "马超", "张飞", "刘备", "诸葛亮", "黄月英", "赵云" }, new Integer[]{ R.mipmap.machao, R.mipmap.zhangfei, R.mipmap.liubei, R.mipmap.zhugeliang, R.mipmap.huangyueying, R.mipmap.zhaoyun } ) ; addInfo("吴", new String[]{ "吕蒙", "陆逊", "孙权", "周瑜", "孙尚香" }, new Integer[]{ R.mipmap.lvmeng, R.mipmap.luxun, R.mipmap.sunquan, R.mipmap.zhouyu, R.mipmap.sunshangxiang } ) ; adapter = new ExpandableListAdapter(this,group,child,logou); expandableListView.setAdapter(adapter); expandableListView.setOnChildClickListener(new ExpandableListView.OnChildClickListener() { @Override public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) { Toast.makeText( ExpandableListActivity.this, "你点击了" + adapter.getChild(groupPosition, childPosition), Toast.LENGTH_SHORT).show(); return false; } }); } /** * 模拟给组、子列表添加数据 */ private void addInfo(String g,String[] c, Integer[] l){ group.add(g); List<String> childitem = new ArrayList<String>(); List<Integer> logouitem = new ArrayList<Integer>(); for(int i=0;i<c.length;i++){ childitem.add(c[i]); logouitem.add(l[i]); } logou.add(logouitem); child.add(childitem); } }
ExpandableListAdapter.java
package com.neon.crm.adapter; import android.content.Context; import android.graphics.Color; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AbsListView; import android.widget.BaseExpandableListAdapter; import android.widget.ImageView; import android.widget.TextView; import com.neon.crm.R; import java.util.List; /** * Created by Administrator on 2017/5/5. * ExpandableListAdapter */ public class ExpandableListAdapter extends BaseExpandableListAdapter{ private Context mContext; private List<String> mGroup; //组列表 private List<List<String>> mChild; //子列表 private List<List<Integer>> mLogou; //子列表 public ExpandableListAdapter(Context context,List<String> group,List<List<String>> child, List<List<Integer>> logou){ this.mContext = context; this.mGroup = group; this.mChild = child; this.mLogou = logou; } // 获得某个父项 @Override public Object getGroup(int groupPosition) { return mGroup.get(groupPosition); } // 获得某个父项的某个子项 @Override public Object getChild(int groupPosition, int childPosition) { return mChild.get(groupPosition).get(childPosition); } // 获得父项的数量 @Override public int getGroupCount() { return mGroup.size(); } // 获得某个父项的子项数目 @Override public int getChildrenCount(int groupPosition) { return mChild.get(groupPosition).size(); } // 获得某个父项的id @Override public long getGroupId(int parentPos) { return parentPos; } // 获得某个父项的某个子项的id @Override public long getChildId(int parentPos, int childPos) { return childPos; } // 按函数的名字来理解应该是是否具有稳定的id,这个方法目前一直都是返回false,没有去改动过 @Override public boolean hasStableIds() { return true; } // 获得父项显示的view @Override public View getGroupView(int groupPosition, boolean isExpanded,View convertView, ViewGroup parent) { View view = convertView; GroupHolder holder = null; if(view == null){ holder = new GroupHolder(); view = LayoutInflater.from(mContext).inflate(R.layout.adapter_expandlist_group_item, null); holder.groupName = (TextView)view.findViewById(R.id.tv_expandlist_group_name); holder.arrow = (ImageView)view.findViewById(R.id.iv_expandlist_group); view.setTag(holder); }else{ holder = (GroupHolder)view.getTag(); } //判断是否已经打开列表 if(isExpanded){ holder.arrow.setBackgroundResource(R.mipmap.ic_arrow_down); }else{ holder.arrow.setBackgroundResource(R.mipmap.ic_arrow_right); } holder.groupName.setText(mGroup.get(groupPosition)); return view; } @Override public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) { View view = convertView; ChildHolder holder = null; if(view == null){ holder = new ChildHolder(); view = LayoutInflater.from(mContext).inflate(R.layout.adapter_expandlist_child_item, null); holder.childAvatar = (ImageView)view.findViewById(R.id.iv_expandlist_child_avatar); holder.childName = (TextView)view.findViewById(R.id.tv_expandlist_child_name); holder.childContent = (TextView)view.findViewById(R.id.tv_expandlist_child_content); holder.divider = (ImageView)view.findViewById(R.id.iv_expandlist_child_divider); view.setTag(holder); }else{ holder = (ChildHolder)view.getTag(); } if(childPosition == getChildrenCount(groupPosition)-1){ holder.divider.setVisibility(View.GONE); } else { holder.divider.setVisibility(View.VISIBLE); } holder.childAvatar.setImageResource(mLogou.get(groupPosition).get(childPosition)); holder.childName.setText(mChild.get(groupPosition).get(childPosition)); holder.childContent.setText(mChild.get(groupPosition).get(childPosition)); return view; } //自己定义一个获得文字信息的方法 TextView getTextView() { AbsListView.LayoutParams lp = new AbsListView.LayoutParams( ViewGroup.LayoutParams.FILL_PARENT, 64); TextView textView = new TextView(mContext); textView.setLayoutParams(lp); textView.setGravity(Gravity.CENTER_VERTICAL); textView.setPadding(80, 0, 0, 0); textView.setTextSize(20); textView.setTextColor(Color.BLACK); return textView; } // 子项是否可选中,如果需要设置子项的点击事件,需要返回true @Override public boolean isChildSelectable(int groupPosition, int childPosition) { return true; } class GroupHolder{ public TextView groupName; public ImageView arrow; } class ChildHolder{ public TextView childName,childContent; public ImageView childAvatar; public ImageView divider; } }
有一下几点需要注意的:
1.设置指示器
有人也许会发现效果图中没有默认箭头(指示器),因为我隐藏了啊~
android:groupIndicator="@null",这样就是设置没有指示器,就是默认的.
如果刚刚的代码,没有设置隐藏指示器就是下图的效果:
(这样就很影响美观,不好看。)
2.自定义指示器
隐藏了就要自定义一个指示器了喔。
在ExpandableAdapter中的getGroupView中参数有一个参数是isExpanded,代表当前Group是否已经打开。
关键代码:
//判断是否已经打开列表
if(isExpanded){
holder.arrow.setBackgroundResource(R.drawable.dowm_arrow);
}else{
holder.arrow.setBackgroundResource(R.drawable.right_arrow);
}
打开了就返回true,没有打开就返回false。
3.默认打开某一个Group
ExpandableListView expandableListView;
...省略获取id得到实例的代码
expandableListView.expandGroup(int)
4.设置每一个item的高度
这个问题困扰了我很久,上面的两个链接也没有明确的说明,于是就百度了半天,终于找出答案了。
但是不知道为什么,要嵌套布局才可以,就是外面一个布局设定高度,里面再设定一个布局也设定高度。然后实际上宽度和高度都是在第二个里设置才有效。
下面是adapter_expandlist_group_item.xml的部分代码:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="70dp" android:gravity="center_vertical" android:paddingLeft="12dp"> <ImageView android:id="@+id/iv_expandlist_group" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@mipmap/ic_arrow_right"/> <TextView android:id="@+id/tv_expandlist_group_name" android:layout_width="wrap_content" android:layout_height="50dp"