美文网首页Android-RecyclerViewAndroid开发安卓
Android 可分组的RecyclerViewAdapter

Android 可分组的RecyclerViewAdapter

作者: donkingliang | 来源:发表于2017-03-23 22:36 被阅读5589次

    转载请说明出处:http://www.jianshu.com/p/302d24db5423

    今天给大家介绍的是一个可以实现数据分组显示的RecyclerViewAdapter:GroupedRecyclerViewAdapter。它可以很方便的实现RecyclerView的分组显示,并且每个组都可以包含组头、组尾和子项;可以方便实现多种Type类型的列表,可以实现如QQ联系人的列表一样的列表展开收起功能等。下面先让我们看一下它所能够实现的一些效果:

    分组的列表 不带组尾的列表 不带组头的列表 子项为Grid的列表 子项为Grid的列表(各组子项的Span不同) 头、尾和子项都支持多种类型的列表 多种子项类型的列表

    还可以很容易的实时列表的展开收起效果:


    可展开收起的列表

    以上展示的只是GroupedRecyclerViewAdapter能实现的一些常用效果,其实使用GroupedRecyclerViewAdapter还可以很容易的实现一些更加复杂的列表效果。在我的GroupedRecyclerViewAdapter项目的Demo中给出了上面几种效果的实现例子,并且有详细的注释说明,有兴趣的同学可以到我的GitHub下载源码。下面直接讲解GroupedRecyclerViewAdapter的使用。

    **1、引入依赖 **
    在Project的build.gradle在添加以下代码

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

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

        compile 'com.github.donkingliang:GroupedRecyclerViewAdapter:1.2.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);
    

    还可是重写GroupedRecyclerViewAdapter方法实现头、尾和子项的多种类型item。效果就像上面的第6张图一样。

        //返回头部的viewType。
        public int getHeaderViewType(int groupPosition);
    
        //返回尾部的viewType。
        public int getFooterViewType(int groupPosition) ;
    
        //返回子项的viewType。
        public int getChildViewType(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;
        }
    

    注意事项:

    1、对方法重写的注意。
    如果我们直接继承RecyclerView.Adapter去实现自己的Adapter时,一般会重写Adapter中的以下几个方法:

    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType);
    
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position);
    
    public int getItemCount();
    
    public int getItemViewType(int position);
    

    但如果是使用GroupedRecyclerViewAdapter,就一定不能去重写这几个方法,因为在GroupedRecyclerViewAdapter中已经对这几个方法做了实现,而且是对实现列表分组至关重要的,如果子类重写了这几个方法,可能会破坏GroupedRecyclerViewAdapter的功能。
    从前面给出的GroupedRecyclerViewAdapter的方法我们可以看到,这些方法其实就是对应RecyclerView.Adapter的这4个方法的,所以我们直接使用GroupedRecyclerViewAdapter提供的方法即可。
    RecyclerView.Adapter中的

        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType);
    
    

    对应GroupedRecyclerViewAdapter中的

        //返回头部的布局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);
    

    这里之所以返回的是布局id而不是ViewHolder ,是因为在GroupedRecyclerViewAdapter项目中已经提供了一个通用的ViewHolder:BaseViewHolder。所以使用者只需要提供布局的id即可,不需要自己去实现ViewHolder。

        @Override
        public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View view = LayoutInflater.from(mContext).inflate(getLayoutId(mTempPosition, viewType), parent, false);
            return new BaseViewHolder(view);
        }
    
        private int getLayoutId(int position, int viewType) {
            int type = judgeType(position);
            if (type == TYPE_HEADER) {
                return getHeaderLayout(viewType);
            } else if (type == TYPE_FOOTER) {
                return getFooterLayout(viewType);
            } else if (type == TYPE_CHILD) {
                return getChildLayout(viewType);
            }
            return 0;
        }
    

    RecyclerView.Adapter中的

        public void onBindViewHolder(RecyclerView.ViewHolder holder, int position);
    

    对应GroupedRecyclerViewAdapter中的

        //绑定头部布局数据。(如果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);
    

    RecyclerView.Adapter中的

        public int getItemCount();
    

    对应GroupedRecyclerViewAdapter中的

        //返回组的数量
        public abstract int getGroupCount();
    
        //返回当前组的子项数量
        public abstract int getChildrenCount(int groupPosition);
    
    

    RecyclerView.Adapter中的

        public int getItemViewType(int position);
    

    对应GroupedRecyclerViewAdapter中的

        //返回头部的viewType。
        public int getHeaderViewType(int groupPosition);
    
        //返回尾部的viewType。
        public int getFooterViewType(int groupPosition) ;
    
        //返回子项的viewType。
        public int getChildViewType(int groupPosition, int childPosition) ;
    

    2、对列表操作的注意
    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 changeDataSet();
    
        //刷新一组数据,包括组头,组尾和子项
        public void changeGroup(int groupPosition);
    
        //刷新多组数据,包括组头,组尾和子项
        public void changeRangeGroup(int groupPosition, int count);
    
        // 刷新组头
        public void changeHeader(int groupPosition);
    
        //刷新组尾
        public void changeFooter(int groupPosition);
    
        // 刷新一组里的某个子项
        public void changeChild(int groupPosition, int childPosition);
    
        //刷新一组里的多个子项
        public void changeRangeChild(int groupPosition, int childPosition, int count);
    
        // 刷新一组里的所有子项
        public void changeChildren(int groupPosition);
    
        //****** 删除操作 *****//
        // 删除所有数据
        public void removeAll();
    
        //删除一组数据,包括组头,组尾和子项
        public void removeGroup(int groupPosition);
    
        // 删除多组数据,包括组头,组尾和子项
        public void removeRangeGroup(int groupPosition, int count);
    
        // 删除组头
        public void removeHeader(int groupPosition);
    
        // 删除组尾
        public void removeFooter(int groupPosition);
    
        //删除一组里的某个子项
        public void removeChild(int groupPosition, int childPosition);
    
        // 删除一组里的多个子项
        public void removeRangeChild(int groupPosition, int childPosition, int count);
    
        //删除一组里的所有子项
        public void removeChildren(int groupPosition);
        
        //****** 插入操作 *****//
        // 插入一组数据
        public void insertGroup(int groupPosition);
    
        //插入一组数据
        public void insertRangeGroup(int groupPosition, int count);
    
        //插入组头
        public void insertHeader(int groupPosition);
        
        // 插入组尾
        public void insertFooter(int groupPosition);
    
        //插入一个子项到组里
        public void insertChild(int groupPosition, int childPosition);
    
        // 插入一组里的多个子项
        public void insertRangeChild(int groupPosition, int childPosition, int count);
    
        //插入一组里的所有子项
        public void insertChildren(int groupPosition);
    

    3、使用GridLayoutManager的注意
    如果要使用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);
    

    4、BaseViewHolder的使用
    项目中提供了一个通用的ViewHolder:BaseViewHolder。提供了根据viewId获取View的方法和对View、TextView、ImageView的常用设置方法。

    //根据id获取View
    TextView  textView = holder.get(R.id.tv_header);
    
    //View、TextView、ImageView的常用设置方法。并且支持方法连缀调用
    holder.setText(R.id.tv_header, "内容")
                    .setImageResource(R.id.iv_image, 资源id)
                    .setBackgroundRes(R.id.view,资源id);
    

    BaseViewHolder是可以通用的,在普通的Adapter中也可以使用,可以省去每次都要创建ViewHolder的麻烦。

    下面看一个简单的使用列子:

    public class GroupedListAdapter extends GroupedRecyclerViewAdapter {
    
        private ArrayList<GroupEntity> mGroups;
    
        public GroupedListAdapter(Context context, ArrayList<GroupEntity> groups) {
            super(context);
            mGroups = groups;
        }
    
        @Override
        public int getGroupCount() {
            return mGroups == null ? 0 : mGroups.size();
        }
    
        @Override
        public int getChildrenCount(int groupPosition) {
            ArrayList<ChildEntity> children = mGroups.get(groupPosition).getChildren();
            return children == null ? 0 : children.size();
        }
    
        @Override
        public boolean hasHeader(int groupPosition) {
            return true;
        }
    
        @Override
        public boolean hasFooter(int groupPosition) {
            return true;
        }
    
        @Override
        public int getHeaderLayout(int viewType) {
            return R.layout.adapter_header;
        }
    
        @Override
        public int getFooterLayout(int viewType) {
            return R.layout.adapter_footer;
        }
    
        @Override
        public int getChildLayout(int viewType) {
            return R.layout.adapter_child;
        }
    
        @Override
        public void onBindHeaderViewHolder(BaseViewHolder holder, int groupPosition) {
            GroupEntity entity = mGroups.get(groupPosition);
            holder.setText(R.id.tv_header, entity.getHeader());
        }
    
        @Override
        public void onBindFooterViewHolder(BaseViewHolder holder, int groupPosition) {
            GroupEntity entity = mGroups.get(groupPosition);
            holder.setText(R.id.tv_footer, entity.getFooter());
        }
    
        @Override
        public void onBindChildViewHolder(BaseViewHolder holder, int groupPosition, int childPosition) {
            ChildEntity entity = mGroups.get(groupPosition).getChildren().get(childPosition);
            holder.setText(R.id.tv_child, entity.getChild());
        }
    }
    
    public class GroupedListActivity extends AppCompatActivity {
    
        private TextView tvTitle;
        private RecyclerView rvList;
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_group_list);
    
            tvTitle = (TextView) findViewById(R.id.tv_title);
            rvList = (RecyclerView) findViewById(R.id.rv_list);
    
            tvTitle.setText(R.string.group_list);
    
            rvList.setLayoutManager(new LinearLayoutManager(this));
            GroupedListAdapter adapter = new GroupedListAdapter(this, GroupModel.getGroups(10, 5));
            adapter.setOnHeaderClickListener(new GroupedRecyclerViewAdapter.OnHeaderClickListener() {
                @Override
                public void onHeaderClick(GroupedRecyclerViewAdapter adapter, BaseViewHolder holder,
                                          int groupPosition) {
                    Toast.makeText(GroupedListActivity.this, "组头:groupPosition = " + groupPosition,
                            Toast.LENGTH_LONG).show();
                }
            });
            adapter.setOnFooterClickListener(new GroupedRecyclerViewAdapter.OnFooterClickListener() {
                @Override
                public void onFooterClick(GroupedRecyclerViewAdapter adapter, BaseViewHolder holder,
                                          int groupPosition) {
                    Toast.makeText(GroupedListActivity.this, "组尾:groupPosition = " + groupPosition,
                            Toast.LENGTH_LONG).show();
                }
            });
            adapter.setOnChildClickListener(new GroupedRecyclerViewAdapter.OnChildClickListener() {
                @Override
                public void onChildClick(GroupedRecyclerViewAdapter adapter, BaseViewHolder holder,
                                         int groupPosition, int childPosition) {
                    Toast.makeText(GroupedListActivity.this, "子项:groupPosition = " + groupPosition
                                    + ", childPosition = " + childPosition,
                            Toast.LENGTH_LONG).show();
                }
            });
            rvList.setAdapter(adapter);
    
        }
    }
    

    这是我在项目Demo中的实现的其中一个列子。效果是上面的图1。想看源码和更多的使用列子的欢迎访问我的GitHub

    头部悬浮吸顶功能
    应一些朋友的反馈,我在1.2.0版本中新加了列表的头部悬浮吸顶功能。使用起来非常的简单,只需要用框架里提供的StickyHeaderLayout包裹一下你的RecyclerView就可以了。当然,你需要使用GroupedRecyclerViewAdapter才能看到效果。

        <!-- 用StickyHeaderLayout包裹RecyclerView -->
        <com.donkingliang.groupedadapter.widget.StickyHeaderLayout
            android:id="@+id/sticky_layout"
            android:layout_width="match_parent"
            android:layout_height="match_parent">
    
            <android.support.v7.widget.RecyclerView
                android:id="@+id/rv_list"
                android:layout_width="match_parent"
                android:layout_height="match_parent" />
        </com.donkingliang.groupedadapter.widget.StickyHeaderLayout>
    

    StickyHeaderLayout提供了一个设置是否显示悬浮吸顶的方法。

        //是否吸顶,默认为true。
        stickyLayout.setSticky(true);
    

    对悬浮吸顶功能的更多介绍,请看我的另一篇文章:《Android RecyclerView实现头部悬浮吸顶效果
    效果图:

    头部吸顶的列表.gif

    相关文章

      网友评论

      • 社会我鹏哥:如果我想在请求接口后,加入分页功能。就是每页查询10条数据,列表拖动到低后再请求接口,然后在屏幕最底下显示“正在加载数据....”;如果服务端最多10条数据,就在屏幕最低下显示”已经到头了“ 请问该怎么实现?????谢谢大神
        社会我鹏哥:前提是我用你的分组列表的依赖库,也能实现吗?
        社会我鹏哥:@donkingliang 谢谢大神
        donkingliang:实现你这个功能需要集成一个下拉刷新和上拉加载的框架。网上有很多这种框架。我今天刚好自己也写了一个。你可以直接用。
        https://github.com/donkingliang/RefreshLayout
        使用还是挺简单的,可以满足你的需求。
      • 小泽老师__:为什么我as里面引用不到?project的build.gradle跟app的build.gradle都写了。就是依赖不到
        donkingliang:@小泽老师__ 有没有看到你的依赖链接后面多了个. :1.2.0. 应该是:1.2.0
        小泽老师__:@donkingliang Error:Unable to resolve dependency for ':app@debug/compileClasspath': Could not resolve com.github.donkingliang:GroupedRecyclerViewAdapter:1.2.0.
        <a href="openFile:C:/Users/admin/AndroidStudioProjects/MyApplication/app/build.gradle">Open File</a><br><a href="Unable to resolve dependency for ':app@debug/compileClasspath': Could not resolve com.github.donkingliang:GroupedRecyclerViewAdapter:1.2.0.">Show Details</a>
        就是报这个。无法依赖。 网络应该没问题,我试了添加其他依赖可以成功。
        donkingliang:@小泽老师__ 只要配置正确,不应该有问题的。有没有可能是网络问题加载失败,或者有没有什么特殊的报错?
      • e38cd76d0ff5:您好,在吗,那个问题不仅仅是通讯录,就是说我自定义的数组超过十条,遍历的时候就会出现空指针错误
        donkingliang:@Hello_Leslie 不是这个博客的原因。如果你是在滚动的时候发生这个问题,那么应该是item的类型错误的问题。你是不是有复写过get****ViewType这几个方法啊。这几个方法返回的值不能有相同,否则会引起类型错误,类型错误会引起item的布局错误,就会发生找不到View等情况。
        e38cd76d0ff5:@donkingliang 嗯啊,谢谢了。这个在布局里面的,数据少的情况下都正常,数据一多,多于十条左右,在滑动界面的时候,就会出现上述错误。https://blog.csdn.net/TianciZhu/article/details/72121685是不是这个原因呢
        donkingliang:你好,我看你的报错信息是item里有一个TextView为空,你可以检查一下你的textview的ID是否在对于的item布局里,或者你可以断点调试一下为空是的情况。这个问题一般是因为布局找不到对应的ID引起的。
      • e38cd76d0ff5:遍历通讯录,通讯录多的情况就出现崩溃
        Process: woxingwoxiu.com, PID: 17687
        java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setText(java.lang.CharSequence)' on a null object reference
        at com.donkingliang.groupedadapter.holder.BaseViewHolder.setText(BaseViewHolder.java:43)
        at woxingwoxiu.com.login.activity.GetPhoneActivity$GroupedListTestAdapter.onBindChildViewHolder(GetPhoneActivity.java:230)
        at com.donkingliang.groupedadapter.adapter.GroupedRecyclerViewAdapter.onBindViewHolder(GroupedRecyclerViewAdapter.java:126)
        at android.support.v7.widget.RecyclerView$Adapter.onBindViewHolder(RecyclerView.java:6673)
        at android.support.v7.widget.RecyclerView$Adapter.bindViewHolder(RecyclerView.java:6714)
        这个怎么解决呢?
      • zp_风:问下不满一行item背景怎么解决,没数据的位置是灰的,感觉好难看
        donkingliang:@zp_风 如果你用第一种的话,你可以把item的分隔线效果写在item里,在每个item里控制分割线。
        zp_风:@donkingliang 感觉。 你说的i第二种我也想过,总感觉还有更的方式,第一种recyclerView 设置背景的话组与组之间分割的颜色怎么控制呢
        donkingliang:你可以把RecyclerView的背景设置成跟item的背影一样。也可以自己计算缺了几个item,然后补充几个只有背景没有内容的item作为占位把一行铺满。比较常用的方案是后者。
      • e38cd76d0ff5:模仿demo测试,出现黑屏,怎么解决,是不是有些地方写错了
        e38cd76d0ff5:已经解决,clean一下就好了
      • d13cd7e656ff:使用GridLayoutManager 如果要使用分割线 怎么使用? 我使用分割线会造成混乱 没有分割线的处理很不方便 无法完美控制和调整子集里面的布局
        donkingliang:@OoTYPoO 为什么不能?把分割线写在item里面,处理它就跟处理普通的item元素是一样的啊。
        d13cd7e656ff:@donkingliang 那应该如何处理??假如我的child 是gridview 无法做到列间距统一啊!???
        donkingliang:是的,我没有提供自定义的ItemDecoration,因为我觉得把分割线的效果写在item里更好处理。
      • 飞天_shine:楼主,我现在第一次获取了分组的数据,但是child的数据,要点击分组的 时候获取,这个怎么办
        donkingliang:@余生_99 会有问题的,因为子列表应该是属于某个分组里面的,不应该独立出来,否则很容易出现问题的。所以你的List<child>最好还是放在对应的分组的数据里面。你的数据应该是一个二级列表的数据结构。
        飞天_shine:在adpter写一个List<child>,写出他的set方法,我在handler 里面获取到数据,调用set方法,然后在适配器的getchild Count方法,直接return child.size(),这样不通过父类的list.get(group positions).getchid.size(). 不会出什么问题吧
        donkingliang:你可以点击分组的时候获取到child的数据,再插入到对应的组,然后刷新列表。但是如果你的child是异步获取得,会延时,那交互体验就没那么好了。
      • b27398973b61:看到说明说不支持任何对列表进行操作的方法,那么有没有类似scrollToPosition(int position)这类的定位组头的方法呢?需求需要在旁边加一个sidebar
        b27398973b61:@donkingliang 好的 谢谢楼主
        donkingliang: "不支持任何对列表进行操作的方法"指的是对列表数据的添加、删除和更新操作,因为这些操作我都要提供新的实现方法了,所以不推荐用RecyclerView原有的方法。但这不影响RecyclerView的其他方法的使用的。你依然是可以使用scrollToPosition()方法的。不过这时候你传入的position应该是列表的实际position,而不是我提供的groupPosition、childPosition。我在GroupedRecyclerViewAdapter里提供了一系列获取列表的实际position的方法。比如获取组头的position的方法getPositionForGroupHeader(int groupPosition)等。你可以看一下源码。
      • 小白进阶:有些子项里还包括子项,一共三级,这个咋弄啊
        donkingliang:子项也是可以支持多种类型的item的。你可以把子项列表看做是一个普通的二级数据列表,并利用不同的子项type显示不同的子项item,达到子项分组显示的目的。不过这时候子项的分组逻辑就要你自己去处理了。
      • 那个唐僧:如果每个组的item的数量不确定怎么做啊,还有就是上拉加载怎么做啊...最近项目里搞这个,烦躁啊....
        佛系猿:addHeaderView,addFooterView 里面没有啊
        那个唐僧:@donkingliang 楼主良心,回复了我不少,我们项目里是返回的数据是动态的key,然后,key的值是中文的,每个key对应的item数量又不相同....把人搞的有点晕..
        donkingliang:我不明白你为什么不能确定每个组的item的数量,因为item的数量完全是有你自己的代码去控制的。如果一个组有组头hasHeader()返回true,如果有组尾hasFooter()返回true,getChildrenCount()返回子项数量。
        至于上拉加载,如果你想自己实现的话,关键在于判断列表是否滚动到底部。思路是监听列表滚动,在滚动停止的时候判断最后可见的item是不是列表的最后一个item(lastVisibleItem == adapter.getItemCount() - 1)。
        如果你不想自己去写上拉加载,网上也有很多基于RecyclerView或嵌套RecyclerView的上下拉框架,你可以搜一下。我自己也有写过上下拉框架,但目前只是在自己和公司的项目用,以后会整理放到GitHub。谢谢!

      本文标题:Android 可分组的RecyclerViewAdapter

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