ExpandableListView万能adapter封装轻松实现分组列表及单选效果

来源:互联网 发布:览物之情得无异乎 编辑:程序博客网 时间:2024/05/29 09:57

在项目开发中有时候会碰到类似于QQ好友列表的分组列表效果的需求,实现的方式有很多种,可以用ListView、RecyclerView等方式实现,其实系统提供了ExpandableListView可以很轻松的实现;ExpandableListView extends ListView所有在用法上和ListView差不多,都需要设置adapter,但是ExpandableListView的adapter需要extends BaseExpandableListAdapter,需要重写里面的getGroupCount()、getChildrenCount()、getGroup()等方法,每写一个adapter就要去重写这些方法,还是挺麻烦的,同时也造成代码的冗余,所有在这里对ExpandableListView adapter进行了封装。

父条目ViewHolder:

public abstract class ParentHolder<T> {    private View convertView;    public ParentHolder() {        convertView = initView();        convertView.setTag(this);    }    public View getConvertView() {        return convertView;    }    @SuppressWarnings("unchecked")    protected <T extends View> T findID(View v, int id) {        return (T) v.findViewById(id);    }    public abstract void refreshView(List<T> list, int position, boolean isExpanded);//初始化页面数据    public abstract View initView();//加载页面ui}

子条目ViewHolder:

public abstract class ChildHolder<T> {    private View convertView;    public ChildHolder() {        convertView = initView();        convertView.setTag(this);    }    public View getConvertView() {        return convertView;    }    @SuppressWarnings("unchecked")    protected <T extends View> T findID(View v, int id) {        return (T) v.findViewById(id);    }    public abstract void refreshView(List<T> list, int position);//初始化页面数据    public abstract View initView();//加载页面ui}

adapter:

public abstract class DefaultAdapter<T> extends BaseExpandableListAdapter {    private Context mContext;    private List<T> parentLists;    private Map<T, List<T>> mMap;    public DefaultAdapter(Context context, List<T> parentList, Map<T, List<T>> map) {        this.mContext = context;        this.parentLists = new ArrayList<>();        if (parentLists != null) {            this.parentLists.addAll(parentList);        }        this.mMap = new HashMap<>();        if (mMap != null) {            this.mMap.putAll(map);        }    }    /**     * 刷新Group数据     *     * @param list     */    public void nodfiyParentData(List<T> list) {        if (list != null) {            this.parentLists.clear();            this.parentLists.addAll(list);        }        notifyDataSetChanged();    }    /**     * 刷新map数据     *     * @param map     */    public void nodfiyMapData(Map<T, List<T>> map) {        if (map != null) {            this.mMap.clear();            this.mMap.putAll(map);        }        notifyDataSetChanged();    }    /**     * 父条目的数量     *     * @return     */    @Override    public int getGroupCount() {        return parentLists.size();    }    /**     * 每个父条目对应的子条目的数量     *     * @param groupPosition     * @return     */    @Override    public int getChildrenCount(int groupPosition) {        T t = parentLists.get(groupPosition);        List<T> ts = mMap.get(t);        if (ts == null) {            ts = new ArrayList<>();        }        return ts.size();    }    /**     * 根据父条目的位置获取对应的对象     *     * @param groupPosition     * @return     */    @Override    public Object getGroup(int groupPosition) {        return parentLists.get(groupPosition);    }    /**     * 根据子条目的位置获取对应的对象     *     * @param groupPosition     * @param childPosition     * @return     */    @Override    public Object getChild(int groupPosition, int childPosition) {        T t = parentLists.get(groupPosition);        List<T> ts = mMap.get(t);        if (ts == null) {            ts = new ArrayList<>();        }        return ts.get(childPosition);    }    /**     * 父位置     *     * @param groupPosition     * @return     */    @Override    public long getGroupId(int groupPosition) {        return groupPosition;    }    /**     * 子位置     *     * @param groupPosition     * @param childPosition     * @return     */    @Override    public long getChildId(int groupPosition, int childPosition) {        return childPosition;    }    @Override    public boolean hasStableIds() {        return true;    }    /**     * 父布局     *     * @param groupPosition     * @param isExpanded     * @param convertView     * @param parent     * @return     */    @Override    public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {        ParentHolder<T> holder = null;        if (convertView == null) {            holder = getParentHolder();        } else {            holder = (ParentHolder<T>) convertView.getTag();        }        //isExpanded group是否有展开        if (groupPosition < parentLists.size()) {            holder.refreshView(parentLists, groupPosition, isExpanded);        }        return holder.getConvertView();    }    protected abstract ParentHolder<T> getParentHolder();    /**     * 子布局     *     * @param groupPosition     * @param childPosition     * @param isLastChild     * @param convertView     * @param parent     * @return     */    @Override    public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {        ChildHolder<T> holder = null;        if (convertView == null) {            holder = getChildHolder();        } else {            holder = (ChildHolder<T>) convertView.getTag();        }        T t = parentLists.get(groupPosition);        List<T> ts = mMap.get(t);        holder.refreshView(ts, childPosition);        return holder.getConvertView();    }    protected abstract ChildHolder<T> getChildHolder();    @Override    public boolean isChildSelectable(int groupPosition, int childPosition) {        //返回true才会触发setOnChildClickListener子条目事件        return true;    }}

以上就是对ExpandableListView adapter的封装,在使用的时候去extends DefaultAdapter 去实现布局view的加载和数据填充就可以了,这样就方便了很多;

public class ExpandableActivity extends AppCompatActivity {    private ExpandableListView expandedList;    private List<DataInfo> pList = new ArrayList<>();    private Map<DataInfo, List<DataInfo>> cMap = new HashMap<>();    private ExpandableAdapter adapter;    private int groupItemSelect = -1;    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_expandable);        setData();        expandedList = (ExpandableListView) findViewById(R.id.expanded_list);        adapter = new ExpandableAdapter(this, pList, cMap);        //设置adapter        expandedList.setAdapter(adapter);        //子条目点击事件        expandedList.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {            @Override            public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {                if (groupItemSelect == -1 || groupItemSelect == groupPosition) {                    setChildSelect(groupPosition, childPosition);                } else {                    setChildSelect(groupPosition, childPosition);                    DataInfo dataInfo2 = pList.get(groupItemSelect);                    List<DataInfo> dataInfos1 = cMap.get(dataInfo2);                    for (DataInfo info : dataInfos1) {                        info.childItemSelect = false;                    }                    cMap.put(dataInfo2, dataInfos1);                }                Toast.makeText(ExpandableActivity.this, "groupPosition-->" + groupPosition + "childPosition-->" + childPosition, Toast.LENGTH_LONG).show();                adapter.nodfiyMapData(cMap);                groupItemSelect = groupPosition;                return false;            }        });        //Group点击事件        expandedList.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {            @Override            public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {                DataInfo dataInfo = pList.get(groupPosition);                Toast.makeText(ExpandableActivity.this, dataInfo.itemTitle, Toast.LENGTH_LONG).show();                return false;            }        });        //设置group左边图标 设置为null代表将其隐藏掉        expandedList.setGroupIndicator(null);        spreadListView();    }    private void setChildSelect(int group, int child) {        DataInfo dataInfo = pList.get(group);        List<DataInfo> dataInfos = cMap.get(dataInfo);        DataInfo dataInfo1 = dataInfos.get(child);        String childItemId = dataInfo1.childItemId;        for (DataInfo info : dataInfos) {            String itemId = info.childItemId;            if (childItemId.equals(itemId)) {                info.childItemSelect = true;            } else {                info.childItemSelect = false;            }        }        cMap.put(dataInfo, dataInfos);    }    /**     * 默认展开第一组 要在setAdapter后调用     */    private void spreadListView() {        int groupCount = adapter.getGroupCount();        if (groupCount > 0) {            expandedList.expandGroup(0);        }    }    /**     * 数据适配器     */    class ExpandableAdapter extends DefaultAdapter<DataInfo> {        public ExpandableAdapter(Context context, List<DataInfo> parentList, Map<DataInfo, List<DataInfo>> map) {            super(context, parentList, map);        }        @Override        protected ParentHolder<DataInfo> getParentHolder() {            return new PHolder();        }        @Override        protected ChildHolder<DataInfo> getChildHolder() {            return new CHolder();        }    }    /**     * group holder     */    class PHolder extends ParentHolder<DataInfo> {        TextView tvGroup;        ImageView ivIcon;        @Override        public void refreshView(List<DataInfo> list, int position, boolean isExpanded) {            DataInfo dataInfo = list.get(position);            tvGroup.setText(dataInfo.itemTitle);            //判断group是否有展开            if (isExpanded) {                ivIcon.setImageResource(R.drawable.up);            } else {                ivIcon.setImageResource(R.drawable.down);            }        }        @Override        public View initView() {            View view = LayoutInflater.from(ExpandableActivity.this).inflate(R.layout.expandable_group, null, false);            tvGroup = findID(view, R.id.tv_group);            ivIcon = findID(view, R.id.iv_icon);            return view;        }    }    /**     * child holder     */    class CHolder extends ChildHolder<DataInfo> {        TextView tvChild;        ImageView ivCheck;        @Override        public void refreshView(List<DataInfo> list, int position) {            DataInfo dataInfo = list.get(position);            tvChild.setText(dataInfo.itemTitle);            boolean childItemSelect = dataInfo.childItemSelect;            if (childItemSelect) {                ivCheck.setImageResource(R.drawable.check);            } else {                ivCheck.setImageResource(R.drawable.uncheck);            }        }        @Override        public View initView() {            View view = LayoutInflater.from(ExpandableActivity.this).inflate(R.layout.expandable_child, null, false);            tvChild = findID(view, R.id.tv_child);            ivCheck = findID(view, R.id.iv_check);            return view;        }    }    private void setData() {        for (int i = 0; i < 5; i++) {            DataInfo info = new DataInfo();            info.itemTitle = "group" + i;            pList.add(info);        }        for (DataInfo dataInfo : pList) {            List<DataInfo> chList = new ArrayList<>();            for (int i = 0; i < 10; i++) {                DataInfo info = new DataInfo();                info.itemTitle = "child" + i;                info.childItemId = dataInfo.itemTitle + "child" + i;                info.childItemSelect = false;                chList.add(info);            }            cMap.put(dataInfo, chList);        }    }

效果如下:
这里写图片描述

源码地址:
http://pan.baidu.com/s/1nuM223v

原创粉丝点击