美文网首页flutterAndroid开发积累安卓UI
Android 可分组的RecyclerViewAdapter

Android 可分组的RecyclerViewAdapter

作者: __素颜__ | 来源:发表于2019-01-31 10:50 被阅读265次

    需求


    image.png

    用listView有分组的展示是ExpandableListView,但是现在都已经不用listview做列表展示了,RecyclerView也有分组展示的Adapter RecyclerViewAdapter。同时也支持头部悬浮吸顶功能

    1、引入依赖

    在Project的build.gradle在添加以下代码

      allprojects {
            repositories {
                ...
                maven { url 'https://jitpack.io' }
            }
        }
    

    在Module的build.gradle在添加以下代码

    compile 'com.github.donkingliang:GroupedRecyclerViewAdapter:1.3.0'
    
    2、继承GroupedRecyclerViewAdapter
    public class GroupedListAdapter extends GroupedRecyclerViewAdapter {
    }
    
    3、实现GroupedRecyclerViewAdapter里的方法

    GroupedRecyclerViewAdapter是一个抽象类,它提供了一系列需要子类去实现的方法。

    //返回组的数量
        public abstract int getGroupCount();
    
        //返回当前组的子项数量
        public abstract int getChildrenCount(int groupPosition);
    
        //当前组是否有头部
        public abstract boolean hasHeader(int groupPosition);
    
        //当前组是否有尾部
        public abstract boolean hasFooter(int groupPosition);
    
        //返回头部的布局id。(如果hasHeader返回false,这个方法不会执行)
        public abstract int getHeaderLayout(int viewType);
    
        //返回尾部的布局id。(如果hasFooter返回false,这个方法不会执行)
        public abstract int getFooterLayout(int viewType);
    
        //返回子项的布局id。
        public abstract int getChildLayout(int viewType);
    
        //绑定头部布局数据。(如果hasHeader返回false,这个方法不会执行)
        public abstract void onBindHeaderViewHolder(BaseViewHolder holder, int groupPosition);
    
        //绑定尾部布局数据。(如果hasFooter返回false,这个方法不会执行)
        public abstract void onBindFooterViewHolder(BaseViewHolder holder, int groupPosition);
    
        //绑定子项布局数据。
        public abstract void onBindChildViewHolder(BaseViewHolder holder,
                                                   int groupPosition, int childPosition);
    
    4、设置点击事件的监听

    GroupedRecyclerViewAdapter提供了对列表的点击事件的监听方法。

      //设置组头点击事件
        public void setOnHeaderClickListener(OnHeaderClickListener listener) {
            mOnHeaderClickListener = listener;
        }
    
        //设置组尾点击事件
        public void setOnFooterClickListener(OnFooterClickListener listener) {
            mOnFooterClickListener = listener;
        }
    
        // 设置子项点击事件
        public void setOnChildClickListener(OnChildClickListener listener) {
            mOnChildClickListener = listener;
        }
    
    5、对列表操作的注意

    RecyclerView.Adapter提供了一系列对列表进行操作的方法。如:

    //更新操作
    public final void notifyDataSetChanged();
    public final void notifyItemChanged(int position);
    public final void notifyItemChanged(int position, Object payload);
    public final void notifyItemRangeChanged(int positionStart, int itemCount);
    public final void notifyItemRangeChanged(int positionStart, int itemCount, Object payload);
    
    //插入操作
    public final void notifyItemInserted(int position);
    public final void notifyItemRangeInserted(int positionStart, int itemCount);
    
    //删除操作
    public final void notifyItemRemoved(int position)
    public final void notifyItemRangeRemoved(int positionStart, int itemCount);
    

    在GroupedRecyclerViewAdapter不建议使用RecyclerView.Adapter的任何对列表的操作方法,因为这些方法都是基于列表的操作,它的position是相对于整个列表而言的,而GroupedRecyclerViewAdapter是分组的列表,它对列表的操作应该是基于组的。同时GroupedRecyclerViewAdapter使用了组结构来维护整个列表的结构,使我们可以对列表进行组的操作,在列表发生变化时GroupedRecyclerViewAdapter需要及时对组结构进行调整,如果使用了RecyclerView.Adapter中的方法对列表进行更新,GroupedRecyclerViewAdapter可能因为无法及时调整组结构而发生异常。所以在使用中应该避免使用这些方法。GroupedRecyclerViewAdapter同样提供了一系列对列表进行操作的方法,我们应该使用GroupedRecyclerViewAdapter所提供的方法。

       //****** 刷新操作 *****//
    
        //通知数据列表刷新。对应 notifyDataSetChanged();
        public void notifyDataChanged();
    
        //通知一组数据刷新,包括组头,组尾和子项
        public void notifyGroupChanged(int groupPosition);
    
        //通知多组数据刷新,包括组头,组尾和子项
        public void notifyGroupRangeChanged(int groupPosition, int count);
    
        // 通知组头刷新
        public void notifyHeaderChanged(int groupPosition);
    
        // 通知组尾刷新
        public void notifyFooterChanged(int groupPosition);
    
        // 通知一组里的某个子项刷新
        public void notifyChildChanged(int groupPosition, int childPosition);
    
        // 通知一组里的多个子项刷新
        public void notifyChildRangeChanged(int groupPosition, int childPosition, int count);
    
        // 通知一组里的所有子项刷新
        public void notifyChildrenChanged(int groupPosition);
    
        //****** 删除操作 *****//
        // 通知所有数据删除
        public void notifyDataRemoved();
    
        // 通知一组数据删除,包括组头,组尾和子项
        public void notifyGroupRemoved(int groupPosition);
    
        // 通知多组数据删除,包括组头,组尾和子项
        public void notifyGroupRangeRemoved(int groupPosition, int count);
    
        // 通知组头删除
        public void notifyHeaderRemoved(int groupPosition);
    
        // 通知组尾删除
        public void notifyFooterRemoved(int groupPosition);
    
        // 通知一组里的某个子项删除
        public void notifyChildRemoved(int groupPosition, int childPosition);
    
        // 通知一组里的多个子项删除
        public void notifyChildRangeRemoved(int groupPosition, int childPosition, int count);
    
        // 通知一组里的所有子项删除
        public void notifyChildrenRemoved(int groupPosition);
        
        //****** 插入操作 *****//
        // 通知一组数据插入
        public void notifyGroupInserted(int groupPosition);
    
        // 通知多组数据插入
        public void notifyGroupRangeInserted(int groupPosition, int count);
    
        // 通知组头插入
        public void notifyHeaderInserted(int groupPosition);
        
        // 通知组尾插入
        public void notifyFooterInserted(int groupPosition);
    
        // 通知一个子项到组里插入
        public void notifyChildInserted(int groupPosition, int childPosition);
    
        // 通知一组里的多个子项插入
        public void notifyChildRangeInserted(int groupPosition, int childPosition, int count);
    
        // 通知一组里的所有子项插入
        public void notifyChildrenInserted(int groupPosition);
    
    6、注意
    //返回头部的布局id。(如果hasHeader返回false,这个方法不会执行)
        public abstract int getHeaderLayout(int viewType);
    
        //返回尾部的布局id。(如果hasFooter返回false,这个方法不会执行)
        public abstract int getFooterLayout(int viewType);
    
        //返回子项的布局id。
        public abstract int getChildLayout(int viewType);
    

    如果有头布局,脚布局hasHeader 和hasFooter一定要返回true

    如果要使用GridLayoutManager,一定要使用项目中所提供的GroupedGridLayoutManager。因为分组列表如果要使用GridLayoutManager实现网格布局,就要保证组的头部和尾部是要单独占用一行的。否则组的头、尾可能会跟子项混着一起,造成布局混乱。同时GroupedGridLayoutManager提供了对子项的SpanSize的修改方法,使用GroupedGridLayoutManager可以实现更多的复杂列表布局。

        //直接使用GroupedGridLayoutManager实现子项的Grid效果
        GroupedGridLayoutManager gridLayoutManager = new GroupedGridLayoutManager(this, 2, adapter);
       rvList.setLayoutManager(gridLayoutManager);
       
    
       GroupedGridLayoutManager gridLayoutManager = new GroupedGridLayoutManager(this, 4, adapter){
           //重写这个方法 改变子项的SpanSize。
           //这个跟重写SpanSizeLookup的getSpanSize方法的使用是一样的。
           @Override
           public int getChildSpanSize(int groupPosition, int childPosition) {
                if(groupPosition % 2 == 1){
                     return 2;
                }
                return super.getChildSpanSize(groupPosition, childPosition);
           }
       };
       rvList.setLayoutManager(gridLayoutManager);
    

    完整代码

    package com.jingdata.investment.ui.schedule.adapter;
    
    import android.content.Context;
    import android.view.View;
    
    import com.donkingliang.groupedadapter.adapter.GroupedRecyclerViewAdapter;
    import com.donkingliang.groupedadapter.holder.BaseViewHolder;
    import com.jingdata.investment.R;
    import com.jingdata.investment.network.bean.ScheduleBean;
    import com.jingdata.investment.network.bean.ScheduleListByBusinessBean;
    import com.jingdata.investment.network.bean.ScheduleUserVOSBean;
    import com.jingdata.investment.utils.DateFormatUtil;
    import com.jingdata.investment.utils.GlobalMethod;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class GroupedListAdapter extends GroupedRecyclerViewAdapter {
        List<ScheduleListByBusinessBean.DataScheduleBean> mGroups = new ArrayList() {
        };
    
        public GroupedListAdapter(Context context, List<ScheduleListByBusinessBean.DataScheduleBean> newResult) {
            super(context);
            mGroups.clear();
            mGroups.addAll(newResult);
        }
    
        public void setData(List<ScheduleListByBusinessBean.DataScheduleBean> newResult) {
            this.mGroups.clear();
            this.mGroups.addAll(newResult);
            notifyDataChanged();
        }
    
        //返回组的数量
        @Override
        public int getGroupCount() {
            return mGroups == null ? 0 : mGroups.size();
        }
    
        //返回当前组的子项数量
        @Override
        public int getChildrenCount(int groupPosition) {
            List<ScheduleBean.ResultBean> dataList = mGroups.get(groupPosition).dataList;
            return dataList == null ? 0 : dataList.size();
        }
    
        //当前组是否有头部
        @Override
        public boolean hasHeader(int groupPosition) {
            return true;
        }
    
        //当前组是否有尾部
        @Override
        public boolean hasFooter(int groupPosition) {
            return false;
        }
    
        //返回头部的布局id。(如果hasHeader返回false,这个方法不会执行)
        @Override
        public int getHeaderLayout(int viewType) {
            return R.layout.item_head_group_schedule;
        }
    
        //返回尾部的布局id。(如果hasFooter返回false,这个方法不会执行)
        @Override
        public int getFooterLayout(int viewType) {
            return 0;
        }
    
        //返回子项的布局id。
        @Override
        public int getChildLayout(int viewType) {
            return R.layout.item_child_group_schedule;
        }
    
        //绑定头部布局数据。(如果hasHeader返回false,这个方法不会执行)
        @Override
        public void onBindHeaderViewHolder(BaseViewHolder holder, int groupPosition) {
            ScheduleListByBusinessBean.DataScheduleBean dataScheduleBean = mGroups.get(groupPosition);
            holder.setText(R.id.tv_head_data, dataScheduleBean.mData);
    
        }
    
        //绑定尾部布局数据。(如果hasFooter返回false,这个方法不会执行)
        @Override
        public void onBindFooterViewHolder(BaseViewHolder holder, int groupPosition) {
    
        }
    
        //绑定子项布局数据。
        @Override
        public void onBindChildViewHolder(BaseViewHolder holder, int groupPosition, int childPosition) {
            //1.设置标题
            ScheduleBean.ResultBean resultBean = mGroups.get(groupPosition).dataList.get(childPosition);
            holder.setText(R.id.tv_title, resultBean.title);
            //2.设置日期
            if (resultBean.startTime != null && resultBean.startTime != null) {
                String startDateString = DateFormatUtil.transForDate(resultBean.startTime, "yyyy-MM-dd HH:mm:ss");
                String endDateString = DateFormatUtil.transForDate(resultBean.endTime, "yyyy-MM-dd HH:mm:ss");
                holder.setText(R.id.tv_data, startDateString + "\n" + endDateString);
            }
            //3.设置参与人
            if (GlobalMethod.isEmpty(resultBean.scheduleUserVOS)) {
                holder.get(R.id.tv_person).setVisibility(View.INVISIBLE);
            } else {
                StringBuffer stringBuffer = new StringBuffer("参与人:");
                for (ScheduleUserVOSBean bean : resultBean.scheduleUserVOS) {
                    stringBuffer.append(bean.firstName);
                    stringBuffer.append("、");
                }
                stringBuffer.deleteCharAt(stringBuffer.length() - 1);
                holder.setText(R.id.tv_person, stringBuffer.toString());
                holder.get(R.id.tv_person).setVisibility(View.VISIBLE);
            }
        }
    
    }
    
    

    activity 中初始化

      mScheduleAdapter = new GroupedListAdapter(mActivity, newResult);
            mScheduleRecyclerView.setLayoutManager(new LinearLayoutManager(mActivity));
            mScheduleRecyclerView.setAdapter(mScheduleAdapter);
    

    相关文章

      网友评论

        本文标题:Android 可分组的RecyclerViewAdapter

        本文链接:https://www.haomeiwen.com/subject/kzbcsqtx.html