BRVAH官方使用指南(持续更新)

作者: 陈宇明 | 来源:发表于2017-06-12 01:50 被阅读243340次
    www.recyclerview.org

    官方网站:www.recyclerview.org

    BRVAH是一个强大的RecyclerAdapter框架(什么是RecyclerView?),它能节约开发者大量的开发时间,集成了大部分列表常用需求解决方案。为什么会有它?请查看「Android开源框架BRVAH由来篇」该框架于2016年4月10号发布的第1个版本到现在已经一年多了,经历了800多次代码提交,140多次版本打包,修复了1000多个问题,获得了9000多star,非常感谢大家的使用以及反馈。
    本篇为BRVAH的使用指南以及包含常见问题会第一时间更新最新的使用方法。最新版本请查看releases,由于持续更新。

    文章目录

    • 框架引入
    • 优化Adapter代码
      和原始的adapter相对,减少70%的代码量。
    • 添加Item事件
      Item的点击事件
      Item的长按事件
      Item子控件的点击事件
      Item子控件的长按事件
    • 添加列表加载动画
      一行代码轻松切换5种默认动画。
    • 添加头部、尾部
      一行代码搞定,感觉又回到ListView时代。
    • 自动加载
      上拉加载无需监听滑动事件,可自定义加载布局,显示异常提示,自定义异常提示。同时支持下拉加载。
    • 分组布局
      随心定义分组头部。
    • 多布局
      简单配置、无需重写额外方法。
    • 设置空布局
      比Listview的setEmptyView还要好用。
    • 添加拖拽、滑动删除
      开启,监听即可,就是这么简单。
    • 树形列表
      比ExpandableListView还要强大,支持多级。
    • 自定义ViewHolder
      支持自定义ViewHolder,让开发者随心所欲。
    • 扩展框架
      组合第三方框架,轻松实现更多需求定制。

    框架引入

    先在 build.gradle(Project:XXXX) 的 repositories 添加:

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

    然后在 build.gradle(Module:app) 的 dependencies 添加:

        dependencies {
                compile 'com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.30'
        }
    

    更新说明:https://github.com/CymChad/BaseRecyclerViewAdapterHelper/releases

    注意

    版本:2.9.28
    Change the method setVisible --> setGone
    The new method setVisible

    setVisible:Set a view visibility to VISIBLE (true) or INVISIBLE (false).
    setGone: Set a view visibility to VISIBLE (true) or GONE (false).

    注意: 一旦出现加载失败的情况,只有两种情况:

    1. 配置没配置好
      配置没配置好,有几种情况:
      1. 只配置了dependencies
      2. 配置repositories,但是位置错了,build.gradle(Project:XXXX) 文件下的repositories有两个,一个是buildscript下面的,一个是allprojects下面的,要配置到allprojects下面才是对的。
      3. 版本号前面多一个v,这个是我的锅,在2.1.2版本之前都是带v的,之后(包含2.1.2)都不需要带v。
    2. 网络原因(这个就不解释了)

    使用Adapter

    和原始的adapter相对,减少70%的代码量。

    使用代码

    public class HomeAdapter extends BaseQuickAdapter<HomeItem, BaseViewHolder> {
        public HomeAdapter(int layoutResId, List data) {
            super(layoutResId, data);
        }
    
        @Override
        protected void convert(BaseViewHolder helper, HomeItem item) {
            helper.setText(R.id.text, item.getTitle());
            helper.setImageResource(R.id.icon, item.getImageResource());
            // 加载网络图片
          Glide.with(mContext).load(item.getUserAvatar()).crossFade().into((ImageView) helper.getView(R.id.iv));
        }
    }
    

    注:如果想深入了解的原理可以查看RecyclerView.Adapter优化了吗?

    使用

    首先需要继承BaseQuickAdapter,然后BaseQuickAdapter<Status, BaseViewHolder>第一个泛型Status是数据实体类型,第二个BaseViewHolder是ViewHolder其目的是为了支持扩展ViewHolder。

    赋值

    可以直接使用viewHolder对象点相关方法通过传入viewId和数据进行,方法支持链式调用。如果是加载网络图片或自定义view可以通过viewHolder.getView(viewId)获取该控件。

    常用方法

    • viewHolder.getLayoutPosition() 获取当前item的position

    常见问题

    这些问题不是使用该库的问题,但是经常有人问这些问题,所以特意写出来,帮助后续遇到以下问题的开发者们。

    为什么有数据不显示?
    请检查一下你的RecyclerView是否设置了LayoutManager。

    为什么有10条数据,只显示1条?
    请检查一下item的布局最外层的Layout是不是layout_height设置了match_parent.

    数据状态错乱
    这个问题无论是RecyclerView还是ListView不做处理都会出现问题,这个本质上是由于布局重用机制导致的,解决办法是通过数据状态来控制控件的状态,一定要设置状态无论什么状态,ifelse是少不了的,如下代码:

      if(entity.isCheck){
        checkBox.isChecked(true);
      } else {
        checkBox.isChecked(false);
      }
    

    解决缓存问题案例:

    添加Item事件


    Item的点击事件
    adapter.setOnItemClickListener(new BaseQuickAdapter.OnItemClickListener() {
                @Override
                public void onItemClick(BaseQuickAdapter adapter, View view, int position) {
                    Log.d(TAG, "onItemClick: ");
                    Toast.makeText(ItemClickActivity.this, "onItemClick" + position, Toast.LENGTH_SHORT).show();
                }
            });
    

    Item的长按事件

    adapter.setOnItemLongClickListener(new BaseQuickAdapter.OnItemLongClickListener() {
                @Override
                public boolean onItemLongClick(BaseQuickAdapter adapter, View view, int position) {
                    Log.d(TAG, "onItemLongClick: ");
                    Toast.makeText(ItemClickActivity.this, "onItemLongClick" + position, Toast.LENGTH_SHORT).show();
                    return false;
                }
            });
    

    注意:嵌套recycleView的情况下需要使用你使用 adapter. setOnItemClickListener 来设置点击事件,如果使用recycleView.addOnItemTouchListener会累计添加的。

    Item子控件的点击事件
    首先在adapter的convert方法里面通过viewHolder.addOnClickListener绑定一下的控件id

     @Override
        protected void convert(BaseViewHolder viewHolder, Status item) {
            viewHolder.setText(R.id.tweetName, item.getUserName())
                    .setText(R.id.tweetText, item.getText())
                    .setText(R.id.tweetDate, item.getCreatedAt())
                    .setVisible(R.id.tweetRT, item.isRetweet())
                    .addOnClickListener(R.id.tweetAvatar)
                    .addOnClickListener(R.id.tweetName)
                    .linkify(R.id.tweetText);
           
        }
    

    然后在设置

     adapter.setOnItemChildClickListener(new BaseQuickAdapter.OnItemChildClickListener() {
                @Override
                public boolean onItemChildClick(BaseQuickAdapter adapter, View view, int position) {
                    Log.d(TAG, "onItemChildClick: ");
                    Toast.makeText(ItemClickActivity.this, "onItemChildClick" + position, Toast.LENGTH_SHORT).show();
                    return false;
                }
            });
    

    Item子控件的长按事件
    步骤同上使用方法不同。
    adapter中绑定方法将addOnClickListener改成addOnLongClickListener.
    设置点击事件方法setOnItemChildClickListener改成setOnItemChildLongClickListener

    注意:设置子控件的事件,如果不在adapter中绑定,点击事件无法生效,因为无法找到你需要设置的控件。

    如果需要在点击事件中获取其他子控件可以使用:

    getViewByPosition(RecyclerView recyclerView, int position, @IdRes int viewId) 
    

    注意:如果有header的话需要处理一下position加上 headerlayoutcount。

    添加列表加载动画

    开启动画(默认为渐显效果)
    adapter.openLoadAnimation();
    默认提供5种方法(渐显、缩放、从下到上,从左到右、从右到左)

    public static final int ALPHAIN = 0x00000001;
        /**
         * Use with {@link #openLoadAnimation}
         */
        public static final int SCALEIN = 0x00000002;
        /**
         * Use with {@link #openLoadAnimation}
         */
        public static final int SLIDEIN_BOTTOM = 0x00000003;
        /**
         * Use with {@link #openLoadAnimation}
         */
        public static final int SLIDEIN_LEFT = 0x00000004;
        /**
         * Use with {@link #openLoadAnimation}
         */
        public static final int SLIDEIN_RIGHT = 0x00000005;
    

    切换动画

    quickAdapter.openLoadAnimation(BaseQuickAdapter.ALPHAIN);
    

    自定义动画

    quickAdapter.openLoadAnimation(new BaseAnimation() {
                                @Override
                                public Animator[] getAnimators(View view) {
                                    return new Animator[]{
                                            ObjectAnimator.ofFloat(view, "scaleY", 1, 1.1f, 1),
                                            ObjectAnimator.ofFloat(view, "scaleX", 1, 1.1f, 1)
                                    };
                                }
                            });
    

    动画默认只执行一次,如果想重复执行可设置

    mQuickAdapter.isFirstOnly(false);
    

    注:如果想深入了解的原理可以查看BaseRecyclerAdapter之添加动画(策略模式)

    设置不显示动画数量

    adapter.setNotDoAnimationCount(count);
    

    首次到界面的item都依次执行加载动画

    由于进入界面的item都是很多的速度进来的所以不会出现滑动显示的依次执行动画效果,这个时候会一起执行动画,如果觉得这样的效果不好可以使用setNotDoAnimationCount设置第一屏item不执行动画,但是如果需要依次执行动画可以重写startAnim让第一个屏幕的item动画延迟执行即可。

    @Override
        protected void startAnim(Animator anim, int index) {
            super.startAnim(anim, index);
            if (index < count)
            anim.setStartDelay(index * 150);
        }
    

    添加头部、尾部


    添加

    mQuickAdapter.addHeaderView(getView());
    mQuickAdapter.addFooterView(getView());
    

    注:如果想深入了解的原理可以查看BaseRecyclerAdapter之添加不同布局(头部尾部)

    删除指定view

    mQuickAdapter.removeHeaderView(getView);
    mQuickAdapter.removeFooterView(getView);
    

    删除所有

    mQuickAdapter.removeAllHeaderView();
    mQuickAdapter.removeAllFooterView();
    

    默认出现了头部就不会显示Empty,和尾部,配置以下方法也支持同时显示:

    setHeaderAndEmpty
    setHeaderFooterEmpty
    

    默认头部尾部都是占满一行,如果需要不占满可以配置:

    setHeaderViewAsFlow
    setFooterViewAsFlow
    

    自动加载

    上拉加载


    // 滑动最后一个Item的时候回调onLoadMoreRequested方法
    setOnLoadMoreListener(RequestLoadMoreListener);
    

    默认第一次加载会进入回调,如果不需要可以配置:

    mQuickAdapter.disableLoadMoreIfNotFullPage();
    

    回调处理代码

    mQuickAdapter.setOnLoadMoreListener(new BaseQuickAdapter.RequestLoadMoreListener() {
                @Override public void onLoadMoreRequested() {
                    mRecyclerView.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            if (mCurrentCounter >= TOTAL_COUNTER) {
                                //数据全部加载完毕
                                mQuickAdapter.loadMoreEnd();
                            } else {
                                if (isErr) {
                                    //成功获取更多数据
                                    mQuickAdapter.addData(DataServer.getSampleData(PAGE_SIZE));
                                    mCurrentCounter = mQuickAdapter.getData().size();
                                    mQuickAdapter.loadMoreComplete();
                                } else {
                                    //获取更多数据失败
                                    isErr = true;
                                    Toast.makeText(PullToRefreshUseActivity.this, R.string.network_err, Toast.LENGTH_LONG).show();
                                    mQuickAdapter.loadMoreFail();
    
                                }
                            }
                        }
    
                    }, delayMillis);
                }
            }, mReyclerView);
    

    加载完成(注意不是加载结束,而是本次数据加载结束并且还有下页数据)

    mQuickAdapter.loadMoreComplete();
    

    加载失败

    mQuickAdapter.loadMoreFail();
    

    加载结束

    mQuickAdapter.loadMoreEnd();
    

    注意:如果上拉结束后,下拉刷新需要再次开启上拉监听,需要使用setNewData方法填充数据。

    打开或关闭加载(一般用于下拉的时候做处理,因为上拉下拉不能同时操作)

    mQuickAdapter.setEnableLoadMore(boolean);
    

    预加载

    // 当列表滑动到倒数第N个Item的时候(默认是1)回调onLoadMoreRequested方法
    mQuickAdapter.setPreLoadNumber(int);
    

    设置自定义加载布局

    mQuickAdapter.setLoadMoreView(new CustomLoadMoreView());
    
    public final class CustomLoadMoreView extends LoadMoreView {
    
        @Override public int getLayoutId() {
            return R.layout.view_load_more;
        }
    
        /**
         * 如果返回true,数据全部加载完毕后会隐藏加载更多
         * 如果返回false,数据全部加载完毕后会显示getLoadEndViewId()布局
         */
        @Override public boolean isLoadEndGone() {
            return true;
        }
    
        @Override protected int getLoadingViewId() {
            return R.id.load_more_loading_view;
        }
    
        @Override protected int getLoadFailViewId() {
            return R.id.load_more_load_fail_view;
        }
    
        /**
         * isLoadEndGone()为true,可以返回0
         * isLoadEndGone()为false,不能返回0
         */
        @Override protected int getLoadEndViewId() {
            return 0;
        }
    }
    
    <?xml version="1.0" encoding="utf-8"?>
    <FrameLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="@dimen/dp_40">
    
        <LinearLayout
            android:id="@+id/load_more_loading_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:gravity="center"
            android:orientation="horizontal">
    
            <ProgressBar
                android:id="@+id/loading_progress"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                style="?android:attr/progressBarStyleSmall"
                android:layout_marginRight="@dimen/dp_4"
                android:indeterminateDrawable="@drawable/sample_footer_loading_progress"/>
    
            <TextView
                android:id="@+id/loading_text"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="@dimen/dp_4"
                android:text="@string/loading"
                android:textColor="#0dddb8"
                android:textSize="@dimen/sp_14"/>
        </LinearLayout>
    
        <FrameLayout
            android:id="@+id/load_more_load_fail_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:visibility="gone">
    
    
            <TextView
                android:id="@+id/tv_prompt"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:textColor="#0dddb8"
                android:text="@string/load_failed"/>
    
        </FrameLayout>
    
    </FrameLayout>
    

    下拉加载(符合聊天软件下拉历史数据需求)


    设置开启开关

     mAdapter.setUpFetchEnable(true);
    

    设置监听

    mAdapter.setUpFetchListener(new BaseQuickAdapter.UpFetchListener() {
                @Override
                public void onUpFetch() {
                    startUpFetch();
                }
            });
    
    private void startUpFetch() {
            count++;
            /**
             * set fetching on when start network request.
             */
            mAdapter.setUpFetching(true);
            /**
             * get data from internet.
             */
            mRecyclerView.postDelayed(new Runnable() {
                @Override
                public void run() {
                    mAdapter.addData(0, genData());
                    /**
                     * set fetching off when network request ends.
                     */
                    mAdapter.setUpFetching(false);
                    /**
                     * set fetch enable false when you don't need anymore.
                     */
                    if (count > 5) {
                        mAdapter.setUpFetchEnable(false);
                    }
                }
            }, 300);
        }
    

    开始加载的位置

    mAdapter.setStartUpFetchPosition(2);
    

    分组布局

    实体类必须继承SectionEntity

    public class MySection extends SectionEntity<Video> {
        private boolean isMore;
        public MySection(boolean isHeader, String header) {
            super(isHeader, header);
        }
    
        public MySection(Video t) {
            super(t);
        }
    }
    

    adapter构造需要传入两个布局id,第一个是item的,第二个是head的,在convert方法里面加载item数据,在convertHead方法里面加载head数据

    public class SectionAdapter extends BaseSectionQuickAdapter<MySection> {
         public SectionAdapter(int layoutResId, int sectionHeadResId, List data) {
            super(layoutResId, sectionHeadResId, data);
        }
        @Override
        protected void convert(BaseViewHolder helper, MySection item) {
            helper.setImageUrl(R.id.iv, (String) item.t);
        }
        @Override
        protected void convertHead(BaseViewHolder helper,final MySection item) {
            helper.setText(R.id.header, item.header);
           
            helper.setOnClickListener(R.id.more, new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Toast.makeText(context,item.header+"more..",Toast.LENGTH_LONG).show();
                }
            });
        }
    

    多布局

    实体类必须实现MultiItemEntity,在设置数据的时候,需要给每一个数据设置itemType

    public class MultipleItem implements MultiItemEntity {
        public static final int TEXT = 1;
        public static final int IMG = 2;
        private int itemType;
    
        public MultipleItem(int itemType) {
            this.itemType = itemType;
        }
    
        @Override
        public int getItemType() {
            return itemType;
        }
    }
    

    在构造里面addItemType绑定type和layout的关系

    public class MultipleItemQuickAdapter extends BaseMultiItemQuickAdapter<MultipleItem, BaseViewHolder> {
    
        public MultipleItemQuickAdapter(List data) {
            super(data);
            addItemType(MultipleItem.TEXT, R.layout.text_view);
            addItemType(MultipleItem.IMG, R.layout.image_view);
        }
    
        @Override
        protected void convert(BaseViewHolder helper, MultipleItem item) {
            switch (helper.getItemViewType()) {
                case MultipleItem.TEXT:
                    helper.setImageUrl(R.id.tv, item.getContent());
                    break;
                case MultipleItem.IMG:
                    helper.setImageUrl(R.id.iv, item.getContent());
                    break;
            }
        }
    
    }
    

    注:如果想深入了解的原理可以查看BaseRecyclerAdapter之添加不同布局(优化篇)

    如果考虑到在GridLayoutManager复用item问题可以配置:

      multipleItemAdapter.setSpanSizeLookup(new BaseQuickAdapter.SpanSizeLookup() {
                @Override
                public int getSpanSize(GridLayoutManager gridLayoutManager, int position) {
                    return data.get(position).getSpanSize();
                }
            });
    

    如果大家觉得这种多布局方式有点由于耦合了实体类,还有支持另外一种多布局方式具体可查看更便捷的多布局, 为 BaseQuickAdapter 设置代理.

    如果使用多布局出现这个NotFoundException异常,有可能是addItemType()两个参数写反了

    设置空布局

    // 没有数据的时候默认显示该布局
    mQuickAdapter.setEmptyView(getView());
    

    如果用网格布局的话,设置空布局就不能给全屏,可以使用瀑布流布局。

    添加拖拽、滑动删除

    拖拽和滑动删除的回调方法

    OnItemDragListener onItemDragListener = new OnItemDragListener() {
        @Override
        public void onItemDragStart(RecyclerView.ViewHolder viewHolder, int pos){}
        @Override
        public void onItemDragMoving(RecyclerView.ViewHolder source, int from, RecyclerView.ViewHolder target, int to) {}
        @Override
        public void onItemDragEnd(RecyclerView.ViewHolder viewHolder, int pos) {}
    }
    
    OnItemSwipeListener onItemSwipeListener = new OnItemSwipeListener() {
        @Override
        public void onItemSwipeStart(RecyclerView.ViewHolder viewHolder, int pos) {}
        @Override
        public void clearView(RecyclerView.ViewHolder viewHolder, int pos) {}
        @Override
        public void onItemSwiped(RecyclerView.ViewHolder viewHolder, int pos) {}
    };
    

    adapter需要继承BaseItemDraggableAdapter

    public class ItemDragAdapter extends BaseItemDraggableAdapter<String, BaseViewHolder> {
        public ItemDragAdapter(List data) {
            super(R.layout.item_draggable_view, data);
        }
    
        @Override
        protected void convert(BaseViewHolder helper, String item) {
            helper.setText(R.id.tv, item);
        }
    }
    

    Activity使用代码

    mAdapter = new ItemDragAdapter(mData);
    
    ItemDragAndSwipeCallback itemDragAndSwipeCallback = new ItemDragAndSwipeCallback(mAdapter);
    ItemTouchHelper itemTouchHelper = new ItemTouchHelper(itemDragAndSwipeCallback);
    itemTouchHelper.attachToRecyclerView(mRecyclerView);
    
    // 开启拖拽
    mAdapter.enableDragItem(itemTouchHelper, R.id.textView, true);
    mAdapter.setOnItemDragListener(onItemDragListener);
    
    // 开启滑动删除
    mAdapter.enableSwipeItem();
    mAdapter.setOnItemSwipeListener(onItemSwipeListener);
    

    默认不支持多个不同的 ViewType 之间进行拖拽,如果开发者有所需求:

    重写ItemDragAndSwipeCallback里的onMove()方法,return true即可

    树形列表

    例子:三级菜单

    // if you don't want to extent a class, you can also use the interface IExpandable.
    // AbstractExpandableItem is just a helper class.
    public class Level0Item extends AbstractExpandableItem<Level1Item> {...}
    public class Level1Item extends AbstractExpandableItem<Person> {...}
    public class Person {...}
    

    adapter需要继承BaseMultiItemQuickAdapter

    public class ExpandableItemAdapter extends BaseMultiItemQuickAdapter<MultiItemEntity, BaseViewHolder> { 
        public ExpandableItemAdapter(List<MultiItemEntity> data) {    
            super(data);
            addItemType(TYPE_LEVEL_0, R.layout.item_expandable_lv0);   
            addItemType(TYPE_LEVEL_1, R.layout.item_expandable_lv1);    
            addItemType(TYPE_PERSON, R.layout.item_text_view);
        }
        @Override
        protected void convert(final BaseViewHolder holder, final MultiItemEntity item) {
            switch (holder.getItemViewType()) {
            case TYPE_LEVEL_0:
                ....
                //set view content
               holder.itemView.setOnClickListener(new View.OnClickListener() {
                   @Override
                   public void onClick(View v) {
                       int pos = holder.getAdapterPosition();
                       if (lv0.isExpanded()) { 
                           collapse(pos);
                       } else {
                           expand(pos);
                       }
               }});
               break;
            case TYPE_LEVEL_1:
               // similar with level 0
               break;
            case TYPE_PERSON:
               //just set the content
               break;
        }
    }
    

    开启所有菜单:

    adapter.expandAll();
    

    删除某一个item(添加和修改的思路是一样的)

    // 获取当前父级位置
     int cp = getParentPosition(person);
    // 通过父级位置找到当前list,删除指定下级
     ((Level1Item)getData().get(cp)).removeSubItem(person);
    // 列表层删除相关位置的数据
     getData().remove(holder.getLayoutPosition());
    // 更新视图
     notifyDataSetChanged();
    

    自定义ViewHolder

    需要继承BaseViewHolder

     public class MovieViewHolder extends BaseViewHolder 
    

    然后修改adapter的第二个泛型为自定义的ViewHolder

    public class DataBindingUseAdapter extends BaseQuickAdapter<Movie, DataBindingUseAdapter.MovieViewHolder>
    

    注意:需要单独建一个外部类继承BaseViewHolder,否则部分机型会出现ClassCastException,如果是内部类的构造方法要是public,定义的那个类也最好是public。

    混淆

    -keep class com.chad.library.adapter.** {
    *;
    }
    -keep public class * extends com.chad.library.adapter.base.BaseQuickAdapter
    -keep public class * extends com.chad.library.adapter.base.BaseViewHolder
    -keepclassmembers  class **$** extends com.chad.library.adapter.base.BaseViewHolder {
         <init>(...);
    }
    

    扩展框架

    由于adapter本身能力有限,我们又不想耦合view层所以有些需求是现实不了,于是合作了一些优秀开源库,为开发者提供更多可能性。以下扩展框架都是有结合BRVAH的demo。

    本文章由于持续更新,建议点赞收藏,便于查看。也欢迎大家提出更多建议,我就会第一时间看到后回复,持续到什么时候?只要还没去领盒饭,我就会持续,😝。

    官方网站:www.recyclerview.org
    Demo下载地址:http://fir.im/s91g

    如果有问题:提问,请先看这个!

    相关文章

      网友评论

      • 719d1f02941b:分页加载最后一页数据会重复
      • 一瞬间的浮华:看到评论都是说的问题,吓得我都不敢用了
      • 43379f12d314:对于多种model 的不适用吧
      • 包二妞:有没有调用这个BRVAH的示例demo???:cold_sweat:
      • Tseng_dc:@陈宇明 请问一下支持复杂的布局作为多type recyclerview的条目吗?比如banner,比如Viewpager
      • 明朗__:设置空状态页 会把头布局也给覆盖
      • 物竞天择_4857:原创你好,分组布局不够清晰 ,有空可否更新下子。
      • 你打野哦:想咨询一个问题也算是需求,如果我想设置Item长按点击触发时间该如何设置,比如说长按5秒后出发长按点击事件?目前是否支持?不支持的如果改?
      • 张_76ac:结合 DataBinding 怎样使用
      • 你好好吖:MultipleItemRvAdapter中构造函数若有传其他参数可以在调用finishInitialize()之前进行赋值,赋值给全局变量 如果调用adapter的setNewData方法 传的值就变null了
      • 敲代码的本愿:错误: 无法访问BaseQuickAdapter
        找不到com.chad.library.adapter.base.BaseQuickAdapter的类文件

        发生了奇怪的问题,能后引用类,编译过不去
      • 4640f78109a4:默认第一次加载会进入回调,如果不需要可以配置:
        mQuickAdapter.disableLoadMoreIfNotFullPage();
        这个方法怎么不管用呢?还是我没有用对?
        哪有什么只是罢了:@Ruikker 同问, 不管用
        82eecd28187a:同问,无法阻止重复加载
      • 5e30a667061c:我可不可以顶你
        ,太赞!
      • m曲终杯盏凉:分割线怎么加
        4d261126ca66:这个要自己加,BRVAH似乎并没有关于分割线的定义
      • 38ee123d3468:现在 gradle 的版本是什么? 我这样导不成功 implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.17'
      • 0156770c53ab:list.add(bean);
        newMealSetAdapter.notifyItemInserted(list.size());
        newMealSetAdapter.notifyItemRangeChanged(list.size(),0);
        请问我这样偶尔会出现数据刷不出来是怎么回事,代码写的有问题吗?只是偶尔出现
      • Ning1994:维护之前人写的代码用到了这个库,
        mAdapter.setOnLoadMoreListener(new BaseQuickAdapter.RequestLoadMoreListener() {
        @Override
        public void onLoadMoreRequested() {
        onLoadData();
        }

        }, recyclerView);
        onLoadMoreRequested一直在被自动调用,知道请求分页接口没有数据返回为止,这是为什么?
        wme_:所以你是怎么解决的呢,我现在用的也是一直回调
        这么近那么远_b67d:@38ee123d3468 关闭的话,我需要加载的时候再怎么调用呢
        38ee123d3468:要关闭加载
      • Jay_Lwp:请问,怎样在外部获取recycleview内部的控件,现在的需求是内部需要修改数据,并不是在内部的convert方法中写死的,我试了在adapter里设置一个方法去改变他的值,但是不行
        Jay_Lwp:@丶SaltedFish 解决了,但不是用这个框架,用原生的recycleview的adapter
        丶SaltedFish:兄弟有解决思路了吗,我也有类似的需求
      • Hangorer:有没有源码
      • 1bfca380e562:有一个问题,我在item里需要给textview添加一个中划线,但是getview之后没有getPaint()
        现在是请问有别的方法么,
        豆浆u条:你可以自己写一个MyBaseViewHolder 然后继承他的BaseViewHolder,然后把一些自定义View的属性和一些没有的View属性在你的MyBaseViewHolder里加上,这样方便调用

        public class MyBaseViewHolder extends BaseViewHolder {

        public MyBaseViewHolder(View view) {
        super(view);
        }

        /**
        * 给TextView添加删除线
        *
        * @param viewId
        * @return
        */
        public BaseViewHolderHelper setTextDeleteLine(@IdRes int viewId) {
        TextView view = getView(viewId);
        view.getPaint().setFlags(Paint.STRIKE_THRU_TEXT_FLAG);
        return this;
        }
        }

        然后你的adapter里这样写就可以了

        public class XXXXAdapter extends BaseQuickAdapter<XXXXBean, MyBaseViewHolder> {
        public XXXXAdapter(@Nullable List<XXXXBean> data) {
        super(R.layout.item_xxx, data);
        }

        @Override
        protected void convert(MyBaseViewHolder helper, XXXXBean item) {
        helper.setTextDeleteLine(R.id.tv_xxx).setText(R.id.tv_xxx, item.getNum());
        }
        }
        3329d8857256:是你用的不对吧?得先转换成TextView 才能用TextView的相关方法 ((TextView)helper.getView(R.id.tv_mirror)).getPaint()...
      • 307b0a7ec431:源码没有重写onBindViewHolder(RecyclerView.ViewHolder holder, int position, List payloads),导致notifyItemChanged(position)刷新整个item,如果有图片会闪一下,体验不好
      • 未来的CEO_kong:第一个问题:感觉不到mAdapter.loadMoreEnd(true)这个方法的作用; 第二个问题: 感觉需要在调用loadmore回调的时候加一个boolean值提供给使用者,因为有的情况不需要加载更多.. 最后总结: 当然我提问的问题,都是用户可以在外层解决的.
      • 娃娃_b7b5:特意登录发个评论点赞的
      • AndZYH:您好,二级列表折叠的时候展示会出现错乱,请问这个如何解决
      • 知吾煮:helper.getView() 有时候拿到控件后报空指针,有时又没有问题
      • edae0eeaa80a:如何结合databinding使用loadmore呢?请指教☺
        65f3933d18d1:我在databinding中也只调用一次loadMore 不知道为什么后面就无法响应了,我尝试换成对recyclerView的滚动监听,却可以用,不知道是为什么
      • 0d15d7fd7e71:给大佬递茶:clap:
      • 善笃有余劫:访问网络 使用 直接刷新数据 为何没有变化
        善笃有余劫:使用 setNewData 刷新
      • 子天666:BaseQuickAdapter中的
        public void remove(@IntRange(from = 0) int position) {
        mData.remove(position);
        int internalPosition = position + getHeaderLayoutCount();
        notifyItemRemoved(internalPosition);
        compatibilityDataSizeChanged(0);
        notifyItemRangeChanged(internalPosition, mData.size() - internalPosition);
        }
        remove方法里为何要notifyItemRangeChanged两次呢?
      • d009154df778:发现一个问题,在convert方法内部有个helper.setOnClickListener监听点击方法,我如果在这个方法前面加个if判断,而且数据是使用addData方法添加的,在helper.setOnClickListener的onClick回调方法内会找不到当前的item
      • 爱在记忆消失前:滑动,多选
      • 爱在记忆消失前:还有滑动选择的功能?
      • helloWorld_ff65:您好,遇到一个问题:树形列表第二级连续打开2个,然后collapse第二个,发现展示的位置有问题,请问如何解决
        AndZYH:您好,我也遇到数据折叠回去展示的位置错乱了,请问您解决了吗
      • Yinll:您好 请问在小米4.4的机型上 为什么会出现setNewData()没有及时更新ui的情况呢?功能时筛选,list集合数据更改后 列表的数据显示时错误的,但是下拉然后再上拉回来后数据显示就正常了,而且在其他机型上不会出现这种情况
      • ccccccal:发现adapter自带了加载更多以及加载结束后没有更多的尾部局,现在我的recycler只有三条数据,不需要什么加载动画和没有更多数据等一切尾部局,这个有什么简单方法嘛
        八怪不姓丑:mAdapter.loadMoreEnd(true);
      • 苦瓜甜瓜:请问大神,有demo的源码吗?我设置了第一页加载不去加载更多disableLoadMoreIfNotFullPage(),但是没效果,第一次还是会去加载更多。
        适当车:找到解决办法了么
      • 简kx:Error:Unable to resolve dependency for ':app@debug/compileClasspath': Could not resolve com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.30.
        <a href="openFile:I:/Android_Study_Path/pro/driver-app/driver/app/build.gradle">Open File</a><br><a href="Unable to resolve dependency for ':app@debug/compileClasspath': Could not resolve com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.30.">Show Details</a>

        一直显示这样 这是怎么回事:flushed:
      • a239e8c5cbc6:那个设置空布局没有全屏显示,是因为那个recyclerView的高设置的不是match_parent,设置成match_parent就好了
      • ljingya:二级列表怎么获取一级列表的位置呢
      • Zcyang:我想问一下,recycleview里item添加RadioGroup选项显示错乱,选择后也会错乱,能请教一下怎么解决么
      • laksg2009:已赞
      • 曾经的你呀:public BaseViewHolder setGone(@IdRes int viewId, boolean visible)
        public BaseViewHolder setVisible(@IdRes int viewId, boolean visible)

        这2个合并起来 public void setVisibility(@Visibility int visibility) 这样会不会好点。?
      • _ljp:外层LinearlayoutManager,嵌套GridViewManager 不能滑动是怎么回事,我用原生的写就没事了哇
      • FlyClound:添加拖拽,如何控制某些元素不可拖拽?
      • 谁的春春不迷茫:作者 你好 如果二级菜单为空了怎么 添加一个空布局
      • 谁的春春不迷茫:作者你好 ,添加脚布局的时候 脚布局设置的布局参数失效 没有正确显示
      • 蜗牛1:gridLayoutManager的情况下加头不是默认头部沾满一行吗?在使用时发现有时候会出现头部下面的上去了setHeaderViewAsFlow(true);的话下面的会上去,为false的话不会会闪一下,这是什么原因啊
      • 8293ecf1ceff:能给不同的item添加不同的背景颜色吗?
      • 年小个大:如果我想在页面上固定一屏显示的个数呢,第一屏我显示4个,滑动一下,切换到后4个item,以此类推。这样如何做到。
        年小个大:是单屏分页滚动功能如何实现
      • Juny_1089:这个框架有下拉刷新吗?
        赖床小能手:@吉原拉面 有下拉刷新
        吉原拉面:这个框架只有上拉加载更多,下拉刷新要配合其他库
      • zhf_花落随:大神呀 大神呀 不知道你还看简书不了,自从有了这个,就迷恋上了,看到布局就是用这个,但是现在有个这样子的布局recyclerview的item里面还有个recyclerview,不是多级的那种,就是现在需要嵌套使用,就不知道怎么使用了,求指教。
        zhf_花落随:@吉原拉面 打错字了 接近 改 解决
        zhf_花落随:@吉原拉面 谢谢 已经接近了,我用的子view是listview,不过目前出现小小的卡顿。
        吉原拉面:你在父recyclerVeiw的adapter的convert()方法里面找到子的recyclerView,然后设置adapter啊
      • _简单一点:`blogAdapter.run {
        isMyLike = true
        bindToRecyclerView(blog_include_rv)
        setOnLoadMoreListener({
        pageIndex++
        blogPresenter.loadMoreDataList(pageIndex)
        }, blog_include_rv)
        setEmptyView(R.layout.recycle_list_empty)
        onItemClickListener = this
        onItemChildClickListener = this
        }`

        这是我在Activity中,关于adapter默认配置的代码,其中setOnLoadMoreListener中的代码不会执行,但是同样的代码我放在Fragment的onActivityCreated的时候,每次刚进入页面setOnLoadMoreListener中的代码就会执行,这个是什么情况啊?求指教
      • 爱在记忆消失前:我如果想清空数据,该怎么调用啊?
      • d05229ae2f0e:楼主你好, 下拉刷新的样式 可以修改吗?
      • 海枫墨:请教下,添加了头部,然后也添加了空布局,如果返回空布局的时候,头部也不显示了,这个如何兼容呢
        吉原拉面:adapter.setHeaderAndEmpty(true)
      • 顶级工程师闯天涯:我突然发现没有支持搜索
      • 唔_aa98:二级列表 子item中有checkbox 上下滑动会错乱 代码如下
        final CheckBox checkBox = helper.getView(R.id.item_download_section_check);
        checkBox.setOnCheckedChangeListener(null);
        checkBox.setChecked(person.isCheck());
        helper.itemView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
        if (checkBox.isChecked()){
        person.setCheck(false);
        checkBox.setChecked(false);
        }else{
        person.setCheck(true);
        checkBox.setChecked(true);
        }
        }
        });
        吉原拉面:view是复用的,你这么搞肯定会错乱,你在数据bean里面加一个属性,比如isChecked,利用data.isChecked来判断是否选中
      • BlueSky01:滑到第15条自动触发checkbox事件,什么原因?
        convert()方法如下:
        helper.setOnCheckedChangeListener(R.id.cb_choose, new CompoundButton.OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
        if(isChecked){

        helper.setTextColor(R.id.cb_choose, Color.parseColor("#357ffa"));
        concern(item.getCurrency_trade_id(),helper);
        }else{

        helper.setTextColor(R.id.cb_choose, Color.parseColor("#aaaaaa"));
        cancelConcern(item.getCurrency_trade_id(),helper);
        }
        }
        });
        BlueSky01:嗯,谢谢:smile:
        jingzx:recyclerView item复用,所以新条目使用的还是之前的checkbox,之前设置的监听事件还在,如果你使用了helper.setChecked(),之前设置的监听就会被促发,如果你需要设置CheckBox的值,可以这样写

        CheckBox checkBox = helper.getView(R.id.cb_choose);
        checkBox.setOnCheckedChangeListener(null);
        checkBox.setChecked(boolean);
        checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {

        }
        });
      • 5db0c34e8781:我发现一个问题。当我执行item的长按事件时,还会触发item点击事件
        5db0c34e8781:@年小个大 真的呢,谢谢!
        年小个大:return true
      • 5b042048f383:大哥,mAdapter.setUpFetchEnable(true); 这个我设置了,监听发下只有第一次自动加载,后面下拉不起作用,使什么情况
      • 2ace8adb9a50:啥都不说了,请大佬喝杯奶茶
      • 4d1dff3b01f7:我做单选,点击某个item 集合中的position 更改为选中状态,其他的更改为取消选中,然后notifyDataSetChanged 去刷新 ,但是 我发现convert 内的数据错乱了,集合中选中的那个状态并没有改变
      • Owen270:大佬,使用CoordinatorLayout+AppBarLayout+RecyclerView组合时,recycleView上啦加载时,使用Adapter的上啦加载方式时,会一直惯性滑动,希望大佬抽空看下
        你们在结婚吗:@Asmewill 可能现象不一样 我用adapter上拉加载时候 进入页面会自动进入上拉刷新
        Owen270:@你们在结婚吗 必须的,强制停止RecycleView的滑动即可
        你们在结婚吗:你解决了没
      • krisian:大神,我遇到这样的一个情况,在刷新的时候,我取到的列表数据不到一页数据,甚至是没有数据,然后列表就会变得很空,但是footer就是显示不出来,感觉是不是调用setNewData()方法的关系。我试过如果不设置refresh.setRefreshing(true),是会显示footer的。有什么办法让在这种情况下,也能显示footer,显示没有更多数据?
        krisian:找到问题了,loadMoreEnd()方法穿的参数的问题
      • Todo2:写的非常不错,赞
        组件化和插件化的开发里程总结
        https://www.jianshu.com/p/df2a6717009d
      • 54a83378d68f:您好,我发现没有介绍不同参数的adapter的构造方法,比如我想实例adapter的时候不想传Bean实体或实体List,只传一个Content,添加数据通过add(bean实体或实体List),这部分内容我找了很久都没找到,希望能解决。
        Power萧君:可以在构造方法new一个空的实体类 之后再add就行了
      • 千万bt:mark了,准备先去研究LZ的代码,本人也深受recyclerview重复代码的折磨.虽然LZ的一些酷炫效果可能会对性能有影响或者因为需求用不到.但是原理学会了的话还是对自己很有用处.跟同事说了这个框架后,在嘲笑我,我们会因为这个控件单独引入这个吗?放心吧,这些东西我们用不到的也不会让你用的balabala....拜托,就算不用你也不想着去优化代码?多花一半的时间写重复的代码?不需要你去用轮子好歹知道轮子怎么造嘛,未来需要轮子的话怎么办?现学?
      • zp_风:您好!问个问题,NestedScrollView 嵌套recyclerView 发现一个问题,NestedScrollView默认焦点在底部, 进来 mAdapter.setOnLoadMoreListener多次调用,这个怎么处理
        zp_风:@千万bt 设置设个无效,有点蛋疼,感觉无解了
        千万bt:给recyclerview设置setFocusable(false)就不会默认在底部
      • 3ed297765c63:楼主 问个初级问题哈 别打我 点击事件只能在adapter外部设置吗 不能在内部吗
        千万bt:可以,不过一些操作需要用到context和一些额外的数据,相对来说在外部进行设置可以降低耦合性,并提高adapter的重用,因为对于不同的类型的数据需要做的操作不一定相同.
      • else_43b1:请问拖动的时候设置拖动的范围,比如往上拖动不能超过第几个,往下不能超过第几个
      • 81987632417f:你好,我想请问一下:使用 StaggeredGridLayoutManager 时,两个position 加载的位置颠倒,如下标2、3 显示为 下标3、2, 这种情况应该如何处理呢??
        81987632417f:自己解决了,不好意思 ... 把加载图片的 Glide.with... 放在 convert(...)第一行就是正确的, 放在set 其他数据的后面, 显示图片的顺序就乱了 。。。
      • 82eecd28187a:大哥您好,在fragment中使用的时候,设置disableLoadMoreIfNotFullPage()仍然会进行一次加载
      • 寝室有人:大神你好,我还是小白现在学习阶段,希望有一个 多布局 的 Demo 可以学习,
        这上面的看不明白如何传入参数,两种item 布局在Recycler 上显示
      • 年小个大:好强大。
      • 锕鎖:可以实现自动换行吗?
      • 寒涵:您好,处理有head的RecycleView item点击事件时,position 要加1是吗,head只有一个
      • 31a5bf98481c:我做一个二级菜单使用了这个,当我点击左侧的recyclerview item切换右边的数据时,数据变了,但是UI展示没变,必须要重新new一个adapter,
        public void setData(List<IndustrySubTitleData> list){
        this.list = list;
        notifyDataSetChanged();
        }
        这样没用,请问有啥好的办法.
      • dee58b038b66:setOnLoadMoreListener一直回调加载更多怎么回事
      • 信徒_d534:数据量多的时候,adapter.addData(list) 明显阻塞主线程。这个怎解决?
      • 改了个名字:public class MyRecylcerViewAdapter extends BaseQuickAdapter<Model,BaseViewHolder>{}
        就这行代码报错 There is no default constructor available in 'com.chad.library.adapter.base.BaseQuickAdapter。
      • 爱在记忆消失前:我去,你弄的框架太牛了吧!:sob:
      • Qy_huang:你好,使用BaseMultiItemQuickAdapter实现3级列表,但是各级列表的layoutmanager 是不一样的,请问怎样设置?
      • 61cd490b6949:很棒,很实用,感谢大神
      • 82eecd28187a:下拉刷新之后会进行一次自动加载更多,这个能否设置可选项呢
      • 张憨憨:这个三级菜单 能不能二级列表中有两个布局啊
      • 欢乐马化腾:删除 滑动的方向 能设置吗,现在是 从左到右,改为 从右往左滑动删除 能设置吗
      • 监控都不:bug巨多,而且使用方法必须按作者意志才能正常使用,在Adapter上做布局相关的工作本来就是一个大大的错误。多布局不比正常Adapter方便多少,上拉下拉刷新加载bug多多。推荐后面的读者不要掉坑了。用正常的继承Adapter和SmartRefreshLayout做上拉下拉操作。
        监控都不:@监控都不 810条评论真的不是说明你的项目有多好,你看评论里多少条是问使用出的问题。这反而反映项目问题多多。
        监控都不:@监控都不 作者应该多从用户角度考虑,优化下结构,真的不是找茬,这框架用在公司项目就是在作死。
        监控都不:此框架让每次写上拉下啦加载页面都是一种痛苦的过程。虽然我用了一次就不用了。
      • 六月L:在使用的时候发现一个我认为不太合理的地方,加载更多:setOnLoadMoreListener() //滑动最后一个Item的时候回调,当我设置了mQuickAdapter.setEnableLoadMore(false);并且当前页面加载了1条后会自动加载第二页,因为最后一个item在当前页面上能显示,感觉打开或关闭加载:mQuickAdapter.setEnableLoadMore(boolean);的优先级应该比滑动到最后一个item自动加载的应该高才对。:grin:
      • 依然赵先生:addFooterView给列表添加一个 可是这样item点击事件就用不了
      • c84a6998a6c6:麻烦问一下,添加的header是固定高度的吗??我用的一个第三方的Banner,设置成header,只能显示标题。
        c84a6998a6c6:@小二木 哈哈,我也用的这个banner,搞不懂为啥,代码设置了LayoutParams才好使
        154db6c439ab:不是吧,自己写死Banner高度试试,我也刚添加了Banner,可以正常显示.
        <com.youth.banner.Banner
        android:id="@+id/banner"
        android:layout_width="match_parent"
        android:layout_height="150dp" />
      • _奶瓶:我想问一下大佬,我想为TextView添加getPaint().setFlags(Paint. STRIKE_THRU_TEXT_FLAG );该如何添加?
        _奶瓶:@Override
        protected void convert(BaseViewHolder helper, BookingHomePageNOTOFragmentBean.DataBean item) {
        helper.setText(R.id.goods_price_text,item.getShop_price());}里面如何添加getPaint().setFlags(Paint. STRIKE_THRU_TEXT_FLAG );
      • 7869ce3afa4a:可以自定义加载更多的布局吗?
      • c5b460f49594:如果一进来数据就是空的 设置setEmptyView的时候就出错了,注释掉就可以了?请问为什么设置setEmptyView会报错呢?
      • c5b460f49594:toMathPlanAdapter.setEmptyView(LayoutInflater.from(getActivity()).inflate(R.layout.nodata, null)); 为什么我调用setEmptyView就出错呢?我在别的项目里也是这样么做的难道是因为在Fragment里面?
      • CLOWN_c0df:楼主,如果哪天你下线了这个框架,我们用的人是不是就要原地爆炸了,有点担忧啊
      • zhuzhiqiang00:大神好,请问一下,添加头部的高度怎么设置啊
      • __Witness:大佬,请教一下,使用item多种布局的时候,不同的item样式的实体类型不一样, 这个怎么使用你的adapter做到
      • FrankDaddy:要是再加上滑动定位就好了:smile:
      • 时间仍在o是我们飞逝:宇明哥,请教个二级列表的问题。在第二级条目中有个控件的值是动态变化的。(适配器中有调用三方SDK下载,然后用sdk下载的回调传回的数据显示到特定控件上)在这种需求下,我是直接settext的,然后发现条目的下载进度出现了复用混乱,有什么好的建议吗宇明哥?很急,github提了ius很久了没人理。。。
      • dc7fe5dcc690:三级菜单怎么添加展开收起的动画

      本文标题:BRVAH官方使用指南(持续更新)

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