美文网首页Android收藏集AndroidAndroid技术
开源框架BaseRecyclerViewAdapterHelpe

开源框架BaseRecyclerViewAdapterHelpe

作者: _猜火车_ | 来源:发表于2017-08-14 00:56 被阅读21852次

前言

  • 主要声明三点

  • 第一:
    关于本文的BaseRecyclerViewAdapterHelper用法,自然是转载的官方原文。或许有的人会很疑惑原文写的那么清除那么完善,为什么我还要写一篇几乎一模一样的?是为了蹭热度让更多的人关注?有更多的点击量?当然不是,我对这么虚伪的东西是非常不齿的。那么自然我有我的原因:

1、我自己其实是个小白,刚入这行不久,由于接触这行时间也不长,加上对这行脑袋瓜比较笨,所以学起来特别吃力,很多东西明明刚用过的,转过头又忘了怎么回事,所以也是特别痛苦;
2、正如第一条所说的,由于太笨,所以想着记录一些笔记来帮助日后的开发,所以.....对,严格意义上来说这只是我的个人学习笔记;
3、当然,由于毕竟是在开源的环境下,相信有的同行搜索相关文章时是会搜到我的文章,所以我写的还是相对比较正规的,如果只是我自己看,我是不会这样记笔记的,以防不幸看到我的文章的童鞋看不懂而吐槽。

  • 第二:
    本文所有内容都是官网上所有的,所以我要特别声明:

1、本文其实只是按照自己的排版习惯重新排版而已;
2、在重写排版的基础上,增加了一些简单的Demo,以及我在写Demo过程中碰上的少量的问题,当然这些问题仅仅是我个人使用的时候碰上的,正如第一条所说的,我本身也是小白,也是在学习阶段,对很多东西也是理解的不够,所以会导致或多或少的问题,所以我像我其他文章一样,我还是强烈建议不幸看到本文的同行去看原文学习使用:BRVAH官方使用指南(持续更新)http://www.jianshu.com/p/b343fcff51b0

  • 第三:
    该适配器虽号称万能适配器,但并非万能,有很多功能本身是实现不了的,还会和其他开源的冲突,比如不能和XRecyclerView一起使用(至少我用的时候是真的冲突)。

  • 第四:
    关于文章中所提到的 "bug",我相信都不存在,只是由于时间关系,无心再去研究,但是我也坚信你继续看本文,还是能够知道该适配器的使用方式的。

一、框架引入

  • 先在项目的 build.gradle(Project:XXXX) 的 repositories 添加:
    allprojects {
        repositories {
            ...
            maven { url "https://jitpack.io" }
        }
    }
  • 然后在Module的 build.gradle(Module:app) 的 dependencies 添加:
    dependencies {
            ......
            compile 'com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.22'
    }
注意: 一旦出现加载失败的情况,只有两种情况:
  • 一是:配置没配置好

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

  • 二是:网络原因(这个就不解释了)

二、Adapter的最基本使用方法

2.1 常用示例代码

  • 和原生的adapter相比,减少70%的代码量。

  • 首先看一段使用示例代码:

public class QuickAdapter extends BaseQuickAdapter<Status, BaseViewHolder> {
    public QuickAdapter() {
        super(R.layout.tweet, DataServer.getSampleData());
    }

    @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())
                .linkify(R.id.tweetText);
                 Glide.with(mContext).load(item.getUserAvatar()).crossFade().into((ImageView) viewHolder.getView(R.id.iv));
    }
}
  • 从上文中的实例代码我们可以看出以下几点:

1、使用: 首先需要继承BaseQuickAdapter,然后BaseQuickAdapter<Status, BaseViewHolder>第一个泛型Status是数据实体类型,第二个BaseViewHolder是ViewHolder其目的是为了支持扩展ViewHolder。
2、赋值:可以直接使用viewHolder对象点相关方法通过传入viewId和数据进行,方法支持链式调用。如果是加载网络图片或自定义view可以通过viewHolder.getView(viewId)获取该控件。

  • 当然这里有一个比较常用的方法:

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

2.2 最基本使用示例Demo

  • 要是刚接触Android的朋友要是还是不知道怎么用,那我这里提供一个很简单的demo:

  • 比如说我想要实现的效果大致如下:


  • 第一步:在布局文件中引入RecyclerView
    activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</RelativeLayout>
  • 第二步:编写条目布局文件
    item_rv.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="5dp">

    <ImageView
        android:id="@+id/iv_img"
        android:layout_width="150dp"
        android:layout_height="80dp" />

    <TextView
        android:id="@+id/tv_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:layout_marginLeft="10dp"
        android:layout_marginTop="10dp"
        android:layout_toRightOf="@+id/iv_img"
        android:text="我是标题"
        android:textColor="#f00"
        android:textSize="20sp" />

    <TextView
        android:id="@+id/tv_content"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/tv_title"
        android:layout_marginLeft="10dp"
        android:layout_marginTop="10dp"
        android:layout_toRightOf="@id/iv_img"
        android:text="我是描述" />
</RelativeLayout>
  • 第三步:编写数据实体类型
    Model.java
public class Model {
    private String title;
    private String content;
    private String imgUrl;

    //生成set、get方法
    ......
}
  • 第四步:编写适配器
    MyAdapter.java
public class MyAdapter extends BaseQuickAdapter<Model, BaseViewHolder> {

    public MyAdapter(@LayoutRes int layoutResId, @Nullable List<Model> data) {
        super(layoutResId, data);
    }

    @Override
    protected void convert(BaseViewHolder helper, Model item) {
        //可链式调用赋值
        helper.setText(R.id.tv_title, item.getTitle())
                .setText(R.id.tv_content, item.getContent())
                .setImageResource(R.id.iv_img, R.mipmap.ic_launcher);

        //获取当前条目position
        //int position = helper.getLayoutPosition();
    }
}
  • 最后一步:在Activity中使用该适配器
    MainActivity.java
public class MainActivity extends AppCompatActivity {

    private RecyclerView recyclerView;
    private List<Model> datas;
    private MyAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //初始化RecyclerView
        recyclerView = (RecyclerView) findViewById(R.id.recycler_view);

        //模拟的数据(实际开发中一般是从网络获取的)
        datas = new ArrayList<>();
        Model model;
        for (int i = 0; i < 15; i++) {
            model = new Model();
            model.setTitle("我是第" + i + "条标题");
            model.setContent("第" + i + "条内容");
            datas.add(model);
        }

        //创建布局管理
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
        recyclerView.setLayoutManager(layoutManager);

        //创建适配器
        adapter = new MyAdapter(R.layout.item_rv, datas);

        //给RecyclerView设置适配器
        recyclerView.setAdapter(adapter);
    }
}
  • OK,运行,得到的效果就是上述的效果。

三、点击事件

  • 上文中描述的就是使用BaseRecyclerViewAdapterHelper最基本的用法,因为怕刚接触Android的兄弟们不明朗或不相信这么简单的用法,所以做了上节简单的demo示例用法。

  • 那么使用列表当然少不了点击事件,不论是整个条目的点击事件还是条目中子控件的点击事件,该适配器对点击事件也是做了及简化的处理:

3.1 条目事件

Item的点击事件

        //条目点击事件
        adapter.setOnItemClickListener(new BaseQuickAdapter.OnItemClickListener() {
            @Override
            public void onItemClick(BaseQuickAdapter adapter, View view, int position) {

                Toast.makeText(MainActivity.this, "点击了第" + (position + 1) + "条条目", Toast.LENGTH_SHORT).show();
            }
        });

Item的长按事件

        //条目长按事件
        adapter.setOnItemLongClickListener(new BaseQuickAdapter.OnItemLongClickListener() {
            @Override
            public boolean onItemLongClick(BaseQuickAdapter adapter, View view, int position) {

                Toast.makeText(MainActivity.this, "长按了第" + (position + 1) + "条条目", Toast.LENGTH_SHORT).show();
                return false;
            }
        });
注意事项
  • 在嵌套recycleView的情况下需要使用你使用 adapter. setOnItemClickListener 来设置点击事件,如果使用recycleView.addOnItemTouchListener会累计添加的。

3.2 条目子控件事件

Item子控件的点击事件

  • 首先:在adapter的convert方法里面通过 helper.addOnClickListener 绑定一下子控件的控件id
    @Override
    protected void convert(BaseViewHolder helper, Model item) {
        //可链式调用赋值
        helper.setText(R.id.tv_title, item.getTitle())
                .setText(R.id.tv_content, item.getContent())
                .addOnClickListener(R.id.iv_img)    //给图标添加点击事件
                .setImageResource(R.id.iv_img, R.mipmap.ic_launcher);
        //获取当前条目position
        //int position = helper.getLayoutPosition();
    }
  • 然后:我们设置
        //条目子控件点击事件
        adapter.setOnItemChildClickListener(new BaseQuickAdapter.OnItemChildClickListener() {
            @Override
            public void onItemChildClick(BaseQuickAdapter adapter, View view, int position) {

                Toast.makeText(MainActivity.this, "点击了第" + (position + 1) + "条条目的图片", Toast.LENGTH_SHORT).show();
            }
        });

Item子控件的长按事件

  • 这里和子控件点击事件是一样的,只是将 点击 变成 长按 就可以了

  • 首先:在adapter的convert方法里面通过 helper.addOnLongClickListener 绑定一下子控件的控件id

    @Override
    protected void convert(BaseViewHolder helper, Model item) {
        //可链式调用赋值
        helper.setText(R.id.tv_title, item.getTitle())
                .setText(R.id.tv_content, item.getContent())
                //.addOnClickListener(R.id.iv_img)    //给图标添加点击事件
                .addOnLongClickListener(R.id.iv_img)//给图片添加长按事件
                .setImageResource(R.id.iv_img, R.mipmap.ic_launcher);
        //获取当前条目position
        //int position = helper.getLayoutPosition();
    }
  • 然后:我们设置
        //条目子控件长按事件
        adapter.setOnItemChildLongClickListener(new BaseQuickAdapter.OnItemChildLongClickListener() {
            @Override
            public boolean onItemChildLongClick(BaseQuickAdapter adapter, View view, int position) {

                Toast.makeText(MainActivity.this, "长按了第" + (position + 1) + "条条目的图片", Toast.LENGTH_SHORT).show();
                return false;
            }
        });
注意事项
  • 设置子控件的事件,如果不在adapter中绑定,点击事件无法生效,因为无法找到你需要设置的控件。

多个Item子控件事件

  • 官方文档上没说,但是 其实这里可以用很常规的方法处理,就是通过判断ID来判定是否是我要的控件?,从而处理不同的事件

  • 比如我这里给 图片和标题 都加点击事件处理不同的逻辑

  • 首先:当然是在适配器中给图片和标题都添加点击事件

 @Override
    protected void convert(BaseViewHolder helper, Model item) {
        //可链式调用赋值
        helper.setText(R.id.tv_title, item.getTitle())
                .setText(R.id.tv_content, item.getContent())
                .addOnClickListener(R.id.iv_img)    //给图标添加 点击事件
                .addOnClickListener(R.id.tv_title)  //给标题也添加 点击事件
                .setImageResource(R.id.iv_img, R.mipmap.ic_launcher);
        //获取当前条目position
        //int position = helper.getLayoutPosition();
    }
  • 其次:
        //条目子控件点击事件
        adapter.setOnItemChildClickListener(new BaseQuickAdapter.OnItemChildClickListener() {
            @Override
            public void onItemChildClick(BaseQuickAdapter adapter, View view, int position) {

                //判断id
                if (view.getId() == R.id.iv_img) {
                    Log.i("tag", "点击了第" + position + "条条目的 图片");
                } else if (view.getId() == R.id.tv_title) {
                    Log.i("tag", "点击了第" + position + "条条目的 标题");
                }
            }
        });
  • 那么如果是长按事件呢?当然也是相同的处理方法。

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

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

比如:

        //条目子控件点击事件
        adapter.setOnItemChildClickListener(new BaseQuickAdapter.OnItemChildClickListener() {
            @Override
            public void onItemChildClick(BaseQuickAdapter adapter, View view, int position) {

                Toast.makeText(MainActivity.this, "点击了第" + (position + 1) + "条条目的图片", Toast.LENGTH_SHORT).show();

                TextView tv_title = (TextView) adapter.getViewByPosition(recyclerView, position, R.id.tv_title);
                Log.i("tag", "当前图片对应的 title=" + tv_title.getText());
            }
        });

        //条目子控件长按事件
        adapter.setOnItemChildLongClickListener(new BaseQuickAdapter.OnItemChildLongClickListener() {
            @Override
            public boolean onItemChildLongClick(BaseQuickAdapter adapter, View view, int position) {

                Toast.makeText(MainActivity.this, "长按了第" + position + "条条目的图片", Toast.LENGTH_SHORT).show();
                TextView tv_title = (TextView) adapter.getViewByPosition(recyclerView, position, R.id.tv_title);
                Log.i("tag", "长按的图片对应的title=" + tv_title.getText());

                return false;
            }
        });

注意:如果有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;
  • 更换动画效果
//使用缩放动画
adapter.openLoadAnimation(BaseQuickAdapter.SCALEIN);
  • 如果想自定义动画,该适配器也提供了接口
        //自定义动画效果
        adapter.openLoadAnimation(new BaseAnimation() {
            @Override
            public Animator[] getAnimators(View view) {
                return new Animator[]{
                        ObjectAnimator.ofFloat(view, "scaleY", 1, 0.5f, 1),
                        ObjectAnimator.ofFloat(view, "scaleX", 1, 0.5f, 1)
                };
            }
        });
  • 注意:动画默认只执行一次,如果想重复执行可设置
//设置重复执行动画
adapter.isFirstOnly(false);
  • 设置不显示动画数量(老实讲,我没明白这个方法的效果是啥,因为我并没有看到效果 0.0)
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(headerView);
mQuickAdapter.addFooterView(footerView);
  • 删除指定view
mQuickAdapter.removeHeaderView(headerView);
mQuickAdapter.removeFooterView(footerView);
  • 删除所有
mQuickAdapter.removeAllHeaderView();
mQuickAdapter.removeAllFooterView();
  • 默认出现了头部就不会显示Empty,和尾部,配置以下方法也支持同时显示:
mQuickAdapter.setHeaderAndEmpty()
mQuickAdapter.setHeaderFooterEmpty();
  • 默认头部尾部都是占满一行,如果需要不占满可以配置:
mQuickAdapter.setHeaderViewAsFlow();
mQuickAdapter.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>

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

1、这里的下拉加载我个人觉得不好用,并不像我们常用的那种下拉加载(当然有可能是我没有合理使用)
2、所以如果是需要下拉刷新的功能,我个人会使用SwipeRefreshLayout

  • 设置开启开关
 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);

八、分组布局

  • 由于我还没碰到过这样的需求,所以对 分组布局 这个概念还不是很了解;

  • 当然,我对概念都不知道,所以也不知道是什么样的效果,当然也就没有写demo(主要是时间问题)。

  • 以下是正文

  • 实体类必须继承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();
            }
        });
    }

九、多布局

  • 多种类型条目的列表是我们日常开发中非常常见的功能,当然该适配器也给我们提供了相应的方法。

  • 使用该适配器设置不同类型条目有两种方式,一种 耦合了实体类,一种是设置代理,这里两种方式我都会演示一遍。

9.1 实现MultiItemEntity的方式

  • 实体类必须实现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;
        }
    }

}
  • 如果考虑到在GridLayoutManager复用item问题可以配置
multipleItemAdapter.setSpanSizeLookup(new BaseQuickAdapter.SpanSizeLookup() {
            @Override
            public int getSpanSize(GridLayoutManager gridLayoutManager, int position) {
                return data.get(position).getSpanSize();
            }
        });
  • 如果使用多布局出现这个NotFoundException异常,有可能是addItemType()两个参数写反了。

  • 以上就是官方文档给出的多布局设置方式的介绍,可能对于像我这样Android小白会看的一脸懵逼,所以我写了一个很简单的Demo方便理解。

Demo实例演示
  • 从上述文档中我们是可以看出来两点

1.我们的数据不直接传给适配器,而是通过MultiItemEntity来传递
2.适配器构造里必须绑定type和layout的关系

  • 废话不多说,演示一个小demo(这里Item布局我就不贴出来了)

第一步:创建MultiItemEntity类

public class MyMultipleItem implements MultiItemEntity {
    public static final int FIRST_TYPE = 1;
    public static final int SECOND_TYPE = 2;
    public static final int NORMAL_TYPE = 3;

    private int itemType;
    private Model data;

    public MyMultipleItem(int itemType, Model data) {
        this.itemType = itemType;
        this.data = data;
    }

    @Override
    public int getItemType() {
        return itemType;
    }

    public Model getData(){
        return data;
    }
}

第二步:创建适配器

public class MultipleItemAdapter extends BaseMultiItemQuickAdapter<MyMultipleItem, BaseViewHolder> {
    
    public MultipleItemAdapter(List data) {
        super(data);
        //必须绑定type和layout的关系
        addItemType(MyMultipleItem.FIRST_TYPE, R.layout.first_type_layout);
        addItemType(MyMultipleItem.SECOND_TYPE, R.layout.second_type_layout);
        addItemType(MyMultipleItem.NORMAL_TYPE, R.layout.item_rv);

    }

    @Override
    protected void convert(BaseViewHolder helper, MyMultipleItem item) {
        switch (helper.getItemViewType()) {
            case MyMultipleItem.FIRST_TYPE:
                Log.i("tag","FIRST_TYPE==============="+helper.getLayoutPosition());
                break;
            case MyMultipleItem.SECOND_TYPE:
                Log.i("tag","SECOND_TYPE==============="+helper.getLayoutPosition());
                break;
            case MyMultipleItem.NORMAL_TYPE:
                helper.setImageResource(R.id.iv_img, R.mipmap.ic_launcher)
                        .setText(R.id.tv_title, item.getData().getTitle())
                        .setText(R.id.tv_content, item.getData().getContent());
                break;
        }
    }
}

第三步:最后当然是在我们的Activity里编写代码

public class MainActivity extends AppCompatActivity {

    private RecyclerView recyclerView;
    private List<Model> datas01;
    private List<MyMultipleItem> datas02;
    private MultipleItemAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //初始化RecyclerView
        recyclerView = (RecyclerView) findViewById(R.id.recycler_view);

        //模拟的假数据(实际开发中当然是从网络获取数据)
        datas01 = new ArrayList<>();
        Model model;
        for (int i = 0; i < 30; i++) {
            model = new Model();
            model.setTitle("我是第" + i + "条标题");
            model.setContent("第" + i + "条内容");
            datas01.add(model);
        }

        datas02 = new ArrayList<>();
        //这里我是随机给某一条目加载不同的布局
        for (int i = 0; i < 30; i++) {
            if (i % 3 == 0) {
                datas02.add(new MyMultipleItem(MyMultipleItem.FIRST_TYPE, null));
            } else if (i % 7 == 0) {
                datas02.add(new MyMultipleItem(MyMultipleItem.SECOND_TYPE, null));
            } else {
                datas02.add(new MyMultipleItem(MyMultipleItem.NORMAL_TYPE, datas01.get(i)));
            }

        }

        //创建布局管理
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
        recyclerView.setLayoutManager(layoutManager);

        //创建适配器
        adapter = new MultipleItemAdapter(datas02);

        //给RecyclerView设置适配器
        recyclerView.setAdapter(adapter);
    }
}

最后:已近完事了,可以运行了,

9.2 为 BaseQuickAdapter 设置代理的方式

  • 从上文中,我们可以知道,其实多布局的本质还是要用某一个变量来区分,上述的方法是使用专门提供得MultiItemEntity接口,让我们实现,从而进行区分;

  • 既然是某一个变量来区分,那我们能不能不实现MultiItemEntity接口,直接在适配器里进行区分呢?

  • 官方还给出了一种方式,给BaseQuickAdapter 设置代理

  • 首先我们先看一下官方给出的文档(分三步)

public class MultiDelegateAdapter extends BaseQuickAdapter<Entity, BaseViewHolder> {

        public MultiDelegateAdapter() {
            super(null);
            //Step.1
            setMultiTypeDelegate(new MultiTypeDelegate<Entity>() {
                @Override
                protected int getItemType(Entity entity) {
                    //根据你的实体类来判断布局类型
                    return entity.type;
                }
            });
            //Step.2
            getMultiTypeDelegate()
                    .registerItemType(Entity.TEXT, R.layout.item_text_view)
                    .registerItemType(Entity.IMG, R.layout.item_image_view);
        }

        @Override
        protected void convert(BaseViewHolder helper, Entity entity) {
            //Step.3
            switch (helper.getItemViewType()) {
                case Entity.TEXT:
                    // do something
                    break;
                case Entity.IMG:
                    // do something
                    break;
            }
        }
    }
  • 可能对于刚接触Android的朋友会看的很懵逼,完全不知道该怎么用,那是因为我们对面向对象的思想理解的还不是很深刻,没关系,这里我也写一个简单的Demo,希望能够帮助理解;
Demo实例演示

首先:我给Model类添加一个变量来区分类型

public class Model {
    public static final int FIRST_TYPE = 1;
    public static final int SECOND_TYPE = 2;
    public static final int NORMAL_TYPE = 3;

    //添加类型变量
    public int type;

    private String title;
    private String content;
    private String imgUrl;

    //set get方法
    ......
}

其次:编写适配器

public class MultiDelegateAdapter extends BaseQuickAdapter<Model, BaseViewHolder> {

    public MultiDelegateAdapter(@Nullable List<Model> data) {
        super(data);
        setMultiTypeDelegate(new MultiTypeDelegate<Model>() {
            @Override
            protected int getItemType(Model entity) {
                //根据你的实体类来判断布局类型
                return entity.type;
            }
        });

        getMultiTypeDelegate()
                .registerItemType(Model.FIRST_TYPE, R.layout.first_type_layout)
                .registerItemType(Model.SECOND_TYPE, R.layout.second_type_layout)
                .registerItemType(Model.NORMAL_TYPE, R.layout.item_rv);
    }

    @Override
    protected void convert(BaseViewHolder helper, Model item) {
        switch (helper.getItemViewType()) {
            case Model.FIRST_TYPE:
                Log.i("tag", "FIRST_TYPE===============" + helper.getLayoutPosition());
                break;
            case Model.SECOND_TYPE:
                Log.i("tag", "SECOND_TYPE===============" + helper.getLayoutPosition());
                break;
            case Model.NORMAL_TYPE:
                helper.setImageResource(R.id.iv_img, R.mipmap.ic_launcher)
                        .setText(R.id.tv_title, item.getTitle())
                        .setText(R.id.tv_content, item.getContent());
                break;
        }
    }
}

最后:在Activity中使用该适配器

public class MainActivity extends AppCompatActivity {

    private RecyclerView recyclerView;
    private List<Model> datas;
    private MultiDelegateAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //初始化RecyclerView
        recyclerView = (RecyclerView) findViewById(R.id.recycler_view);

        //模拟的假数据(实际开发中当然是从网络获取数据)
        datas = new ArrayList<>();
        Model model;
        for (int i = 0; i < 30; i++) {
            model = new Model();
            model.setTitle("我是第" + i + "条标题");
            model.setContent("第" + i + "条内容");

            //这里随机给某一条目设置不同布局类型
            if (i == 3 || i == 10 || i == 13) {
                model.setType(Model.FIRST_TYPE);
            } else if (i == 5 || i == 8 || i == 20) {
                model.setType(Model.SECOND_TYPE);
            } else {
                model.setType(Model.NORMAL_TYPE);
            }
            
            datas.add(model);
        }


        //创建布局管理
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
        recyclerView.setLayoutManager(layoutManager);

        //创建适配器
        adapter = new MultiDelegateAdapter(datas);

        //给RecyclerView设置适配器
        recyclerView.setAdapter(adapter);
    }
}
  • OK,运行结果应该是:第4、11、14条目显示的是同一种类型布局,第6、9、21条目显示的是另一种类型布局,其它条目显示的又是另一种类型布局。

十、设置空布局

  • 就一个方法,没有数据时就默认显示该布局:
// 没有数据的时候默认显示该布局
mQuickAdapter.setEmptyView(getView());
  • 设置空布局就一个方法,但是我还是单独放在一个章节里来讲也是有原因的:

1、在我写demo的时候,设置空布局时就碰上一个bug,即使我所有的布局中的相关控件高度都设置成填充父窗体,但是显示时并没有填充整个界面,而仅仅是包裹内容;
2、但是当我在我现在开发的项目中设置空布局时又确实是填充整个父窗体,这就让我很迷惑了,狂躁了好久,看了好多次demo代码也没找到原因,最后还是没有找到原因.......
3、当然,因为我也是一个Android新人,有很多地方我都需要继续努力学习,或许只是一个很简单、很低级的错误导致没有填充父窗体,如果看到这篇文章的朋友你也遇到过相似的问题,而且又正好知道原因,还希望你能多多指教。

十一、添加拖拽、滑动删除

  • 本人测试了一下,拖拽交换位置效果不错,但是滑动删除效果我测试的是有问题的,条目显示会错乱,被删除的条目还会出现空白条目现象.......(疑惑)不知道是不是我打开方式不对???

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

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即可

十二、树形列表

  • 本人表示不想贴出demo了,因为我没尝试着写demo试试,看文档说明感觉和多布局貌似是一个套路....(感觉是...)

  • 例子:三级菜单

// 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。

十三、扩展框架

结束语

相关文章

网友评论

  • 微小的沙土:有没有嵌套rv用法,我在convert里找到内层rv,然后添加item边距,重用出问题了
    微小的沙土:@猜火车_ 嗯,解决了,复用重复运行convert,然后我获取rv设置边距一直new itemDe... 结果导致间距一直变大!解决方法是在Adapt构造方法里就初始化出这个itemDe...,然后在convert里先remove再add回去,这样重用就没问题了
    _猜火车_:@UnknownError 添加item边距?你的意思是动态吗?其实嵌套rv时你就通过getView获取内部rv然后再设置适配器就行,这个不会有什么大问题的。如果是复用出问题,只会是你代码问题,列表问题一定要有if-else的
  • Guow110:adapter.disableLoadMoreIfNotFullPage(); 这个 方法好像是不生效,怎么破
  • winelx:有遇见传递的list在填的时候变成空的吗?
  • 山峰01:哥哥快来啊 加我好友 你懂得
    _猜火车_:@山峰01 峰哥,你个逗逼
  • 3f83064f7965:No adapter attached; skipping layout
  • c8d91a42c3cd:博主能不能加个联系方式或者发送一个联系方式,我这个拖拽出不来效果,我想请教下你。178677610 178677610@qq.com
  • 154db6c439ab:请教一个加载多布局的问题,后台返回10条的列表数据,我这样加载多布局成功后为什么原来10条的数据只有9条了?
    //加载多布局
    for (int i = 0; i < articleInfoBean.size(); i++) {
    HomeBean.ArticleInfoBean bean = articleInfoBean.get(i);
    if (i == 3) {
    bean.setLayoutType(HomeBean.ArticleInfoBean.SECOND_TYPE); //在第四条item设置第二种布局
    } else {
    bean.setLayoutType(HomeBean.ArticleInfoBean.NORMAL_TYPE);//默认第一种布局
    }
    }
    //TODO:布局一数据少了一条
    LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity());
    linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
    DividerItemDecoration mDividerItemDecoration = new DividerItemDecoration(getActivity(), linearLayoutManager.getOrientation());
    mRecyclerView.addItemDecoration(mDividerItemDecoration);
    mRecyclerView.setLayoutManager(linearLayoutManager);
    mRecyclerView.setAdapter(mAdapter);// 设置文章列表数据
    // mAdapter.notifyItemChanged(2,articleInfoBean.size());
    // mAdapter.notifyItemChanged(3);
    // mAdapter.notifyItemRangeChanged(2,articleInfoBean.size());
    154db6c439ab:@猜火车_ 麻烦帮我看一下,适配器中我是这样写的:构造中: setMultiTypeDelegate(new MultiTypeDelegate<HomeBean.ArticleInfoBean>() {
    @Override
    protected int getItemType(HomeBean.ArticleInfoBean homeListBean) {
    return homeListBean.layoutType;//根据你的实体类来判断布局类型;
    }
    });
    getMultiTypeDelegate()//设置Recycler不同类型对应的布局文件
    .registerItemType(HomeBean.ArticleInfoBean.NORMAL_TYPE, R.layout.item_home_page)//默认布局(第一种布局类型)
    .registerItemType(HomeBean.ArticleInfoBean.SECOND_TYPE, R.layout.today_read);//第二种布局(今日必读)
    convert方法中: switch (helper.getItemViewType()) {
    case HomeBean.ArticleInfoBean.NORMAL_TYPE: //默认布局
    RequestOptions options = new RequestOptions().placeholder(R.mipmap.temp_banner);
    helper.setText(R.id.tv_headerline_title, item.getTitle())//标题
    .setText(R.id.tv_headerline_watch_count, String.valueOf(item.getArticle_hits()));//点击数
    Glide.with(mContext).load(item.getLeftFigure()).apply(options).into((ImageView) helper.getView(R.id.iv_headerline));//文章图片
    break;

    case HomeBean.ArticleInfoBean.SECOND_TYPE: //第二种布局
    RecyclerView recyclerView = helper.getView(R.id.rv_today_read);
    LinearLayoutManager linearLayoutManager = new LinearLayoutManager(mContext);
    linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
    recyclerView.setLayoutManager(linearLayoutManager);
    if (mAdapter == null) {
    mAdapter = new TodayReadAdapter(R.layout.item_today_read, mHomeBean.getMustRead());
    recyclerView.setAdapter(mAdapter);
    }
    mAdapter.setOnItemClickListener(this);
    break;
    }
    _猜火车_:@小二木 从目前你的代码中看,少了的一条应该是第四条,如果是第四条说明你适配器中没做好类型处理…如果不是,那这点代码我也看不出来有啥问题,你可以进官网的群里问题反馈里去找找答案…当然你也可以提供更多的代码,我试着找原因
  • zp_风:您好!问个问题,NestedScrollView 嵌套recyclerView 发现一个问题,NestedScrollView默认焦点在底部, 进来 mAdapter.setOnLoadMoreListener多次调用,这个怎么处理
  • 橙果子:讲解的清晰明了,给个赞
  • aaaaaaa12:你好,我现在实现了拖动,但是点击监听却没用了,需要怎么修改?
    _猜火车_:@欢乐时光_86fc 不好意思,我比较忙,暂时没有时间管你,拖拽和删除出问题的主要原因是数据源没有跟着做对应的操作,你注意一下,另外,有问题还是尽量去原博客的问题交流区找找答案,本文仅仅演示最基本的使用方法,有一些注意事项及更深层次的东西没时间去更新。不好意思,望理解
    c8d91a42c3cd:你好,能交流一下拖拽么
  • qquser_d336:车车,加载成功后会默认回到顶面,怎么让他保持在将刷新的地方
    kwondo:@qquser_d336 使用adapter.addData()方法
    qquser_d336:@猜火车_ 我每次请求成功后用的addAll,数据显示正常,可是列表刷新到最顶端
    _猜火车_:@qquser_d336 (•̀⌄•́) 车车?这叫法让我很害羞呢。◕‿◕。 加载更多只是一种功能,和你列表位于哪没有直接关系,我觉得你是加载更多请求成功回来的数据添加时方式错误了,这个时候应该是add而不是set,用add是不会出现你这个问题的
  • 0cf63a0e4a8d:是只能有一个LayoutManager么,如果是需要两层列表 外面竖的套横向列表呢
  • 寒涵:如果有header的话需要处理一下position加上 headerlayoutcount。
    这个header如果是addHeaderView增加的也要算position吗?
    _猜火车_:@寒涵 不算,你可以试着获取试试
  • 行云流水之灵:大神,在NestedScrollView嵌套下,第一次进来就调用的onLoadMoreRequested方法,但是没有显示加载更多的布局,向下滑动,再上拉的时候,又可以看着加载更多的布局了。不知道是什么回事,请指点一二!
    zp_风:我也遇到了跟你一样的问题,你最后怎么解决的,感谢!试过过添加NestedScrollView这个滑动到底部监听加载更多数据,发现用这个框架不知道到怎么处理加载更多的视图
    行云流水之灵:@猜火车_ 谢谢了。在NestedScrollView嵌套recyclerview,在一进来就开始加载更多,然后没有看着加载完成的脚布局,在滑到顶部,在滑到底部就看到了!
    _猜火车_:@行云流水之灵 表示不是很理解你的用法,抱歉
  • Destiny_ZRJ:怎么在外部获取子控件额··?为什么我用getViewByPosition 返回控件为null,就是比如我从后台取出来一个列表数据,有name 和content ,name是从后台拿到数据插入的,而content是我这边插入的
    Destiny_ZRJ:@猜火车_ 对对,老哥,是哪个方法。。。我没有看到:sob: 感谢
    _猜火车_:@Destiny_ZRJ 你的意思就是要改变某个条目数据吗?有这个方法哦
    Destiny_ZRJ:只能在点击事件里面获取子控件吗?
  • Solomemory:请问一下,怎么设置item的选中状态呢?单选状态,下面我的做法是这样,但是每个都会被选中
    adapter.setOnItemClickListener(new BaseQuickAdapter.OnItemClickListener() {
    @Override
    public void onItemClick(BaseQuickAdapter adapter, View view, int position) {
    view.setSelected(true);
    }
    });
    _猜火车_:@Solomemory 大哥…你这…怎么说呢,看在你是新手的份上我还是帮帮你吧,本来是你自己的事,和适配器无关。有好多种方式,比如在modul中用一个字段区分,适配器中通过if else判断,我只能说到这了,不懂的话问问你身边的人吧
  • zhuzhiqiang00:大神好,请问一下 ,addHeaderView时,如何设置头部的高度啊
    _猜火车_:@zzqFive 好吧 额 这个问题我记得我貌似在笔记中有说明,刚刚翻了一下 貌似没有 那就是我的私人笔记中记录了 这篇文章确实该更新了:flushed: 根节点的ViewGroup宽和高是会被忽略的 简单来说宽和高会从第二层开始计算
    zhuzhiqiang00:@猜火车_ 可以了,要这样才行<?xml version="1.0" encoding="utf-8"?>

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android";
    xmlns:app="http://schemas.android.com/apk/res-auto";
    android:layout_width="match_parent"
    android:layout_height="200dp">

    <com.youth.banner.Banner
    android:id="@+id/banner"
    android:layout_width="match_parent"
    android:layout_height="200dp"
    app:is_auto_play="true" />

    </LinearLayout>

    下面这样不可以
    <?xml version="1.0" encoding="utf-8"?>

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android";
    xmlns:app="http://schemas.android.com/apk/res-auto";
    android:layout_width="match_parent"
    android:layout_height="200dp">

    <com.youth.banner.Banner
    android:id="@+id/banner"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:is_auto_play="true" />

    </LinearLayout>
    或者这样也不行
    <?xml version="1.0" encoding="utf-8"?>

    <com.youth.banner.Banner xmlns:android="http://schemas.android.com/apk/res/android";
    xmlns:app="http://schemas.android.com/apk/res-auto";
    android:id="@+id/banner"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:is_auto_play="true" />
    _猜火车_:@zzqFive ………大哥,这问题太简单了吧?这是一个view,view的高度要么在xml文件中声明,要么在代码中动态设置…
  • a9c753ef15ef:问一下老哥:getViewByPosition这个方法获取不到不在屏幕内的条目信息,如何才能获取到呢?或者用什么方法可以获取到?
    _猜火车_:再有,如果你是想得到数据 那么直接取适配器的数据就行了 因为你条目信息也是根据此时适配器里的数据来填充的 所以。。。。两个方法。。。总有一个能解决你的问题
    _猜火车_:你在哪里要获取条目信息?如果是点击事件时,那么回调中直接就有给你返回条目的View了,这个View就是条目布局最外层的ViewGroup了,遍历这个ViewGroup就可以得到里面的子控件了 别问我怎么遍历ViewGroup。。。上网搜
  • 154db6c439ab:你好!请问为什么我这样加载更多不行呢?加载更多的JSON数据是成功打印出来了的.
    private void setLoadMoreData(String json) {
    //目前处于子线程
    Gson gson = new Gson();
    final HomeListBean homeListBean = gson.fromJson(json, HomeListBean.class);
    final List<HomeListBean.DataBean> data = homeListBean.getData();
    // mDatas = new ArrayList<>();
    final int totalCount = mCurrentCounter + data.size();//视频总条数
    getActivity().runOnUiThread(new Runnable() {
    @Override
    public void run() {
    if (mCurrentCounter >= totalCount) {
    //数据全部加载完毕
    homeAdapter.loadMoreEnd();
    } else {
    if (isErr) {
    homeAdapter.addData(homeListBean);
    mCurrentCounter = homeAdapter.getData().size();
    //主动调用加载完成,停止加载
    homeAdapter.loadMoreComplete();
    } else {
    //获取更多数据失败
    isErr = true;
    //同理,加载失败也要主动调用加载失败来停止加载(而且该方法会提示加载失败)
    homeAdapter.loadMoreFail();
    }
    _猜火车_:@小二木 听你的意思就是你在子线程做更新UI的操作吧 ?
    154db6c439ab:@猜火车_ 调用了加载更多的监听,而且已经获取到加载更多的数据了,就是设置的问题.我是在onLoadMoreRequested()方法内做网络请求,然后获取到加载更多的数据,之前那段代码就是设置加载更多数据的.请问是否有详细一点的加载更多示例呢?
    _猜火车_:你调用了加载更多的监听了吗?加载更多的代码是要在监听里写的,比如你请求数据的方法叫 requestData(),那你要在监听里去调用这个方法(PS:你给我贴出的代码只是处理接收到数据后适配器的加载状态)
  • 口袋不插花:文档写的很详细,真的给予很大的帮助,谢谢作者。哭,是贫穷限制了我给你打赏,请勿@我
    _猜火车_:哈哈 要打赏也是给作者打赏,我只是寄了个笔记而已,而且文中有好多不完善和缺陷的地方 我一直都没时间重新整理一遍
  • 痞子1号:您好 setEmptyView 不居中 这个怎么解决 网上试过几种方法 都不行 请指教
    7ab57de8894c:recycleView填充满屏幕,你让你的空布局填充满屏幕,在空布局里把你想居中的内容居中
    _猜火车_:@痞子1号 这个问题不看代码是无法判断的,你说的这个问题我其实也碰到过,我当时也没找到原因,总之就是从最外层到最里层都看看宽高设置。
  • 154db6c439ab:请问一下,如果我的item中嵌套了GridView该怎么设置?例如常用的是这样: //可链式调用赋值
    helper.setText(R.id.tv_title, item.getTitle());
    // .setText(R.id.tv_content, item.getContent())
    // .setImageResource(R.id.iv_img, R.mipmap.ic_launcher);
    _猜火车_:@小二木 我嵌套过,并没有卡的现象,只是可能子RecyclerView会抢焦点,可能会造成自动会滚动的效果一样,这个可以设置子RecyclerView.setFucausboble(false)来解决,至于你说的会卡死的现象,我觉得并不是RecyclerView嵌套RecyclerView直接造成的,而是你代码本身有一定问题。
    154db6c439ab:@猜火车_ 谢谢!按照你说的item嵌套GridView改为RecyclerView确实可以,item内嵌套那个RecyclerView的Adatper也是我也是创建类去继承BaseQuickAdapter.还想请教一下,我这样嵌套真机上可以流畅滑动,但是用夜神模拟器会卡死,这是RecyclerView嵌套RecyclerView造成的冲突吗?
    _猜火车_:@小二木 你好,不好意思 刚看到。如果我没理解错的话,你的意思就是说怎么获取GridView是吧? 获取了GridView然后又设置适配器是吧? 你可以用GridView
    gridView=helper.getView(R.id.grid_view);的方式获取GridView 然后在给GridView设置适配器就行了。 再有 建议你要嵌套也别嵌套GridView,可以接着嵌套RecyclerView的方式,RecyclerView本身就是替代ListView和GridView的功能的,如果不会用RecyclerView写成GridView的效果,可以参考我的另一篇文章 RecyclerView的完全解析,当然也可以搜搜更全面地博客来学习使用。希望可以帮到你,如果我没帮上你的问题,请尽量描述清楚问题。
  • 冬虫不可以语夏:如果我的RecyclerView 只有2条数据,怎么去隐藏 没有更多数据 这句话呢 ? 谢谢
    冬虫不可以语夏:@猜火车_ 现在我是 SwipeRefreshLayout 包裹一个ScrollView ,ScrollView里面包裹RecyclerView,想实现RecyclerView的上啦加载,您有什么好的建议吗?谢谢
    冬虫不可以语夏:@猜火车_ adapter.notifyItemRemoved(adapter.getItemCount()); 这句好用吗
    _猜火车_:@不知寒号 你好,不好意思,刚看到。你说的没有更多数据这句话应该是设置了上拉加载更多数据这个方法才有的,关于上拉加载,我个人有两个建议。1、可以通过获取的数据是否多余多少条时才设置上拉加载更多的功能,这个就是说在你获取数据后再来决定是否设置上拉加载更多的功能。2、可以不用该适配器本身的上拉加载功能,可以使用其他第三方来实现上拉加载或者下拉刷新的功能,这个在文章最后也有提供其他第三方优秀库的,你可以选择。
  • 683e49c298b5:请问,使用多级菜单的时候,只能同时展开一个列表的功能怎么实现
    _猜火车_:这个功能应该就是树形列表,你去看看第十二章的树形列表,或者直接去原文查看一下。由于当时我写这篇文章的时候时间问题,像分组列表和树形列表都没贴出demo,所以还望能参考文档自己实现。:blush:
  • 赵sir_bd88:大佬,用这个框架复用问题你是怎么解决的。
    _猜火车_:@赵sir_bd88 这个框架已经帮你解决了 你完全不用考虑这个问题,你只需要填充对应的数据就OK了。要是连复用都没解决,这个框架也没人用啊:flushed:
  • X_sky_B:设置了加载更多,不走回调是什么原因
  • 30c78afc928b:请问你当时有没有试过setUpFetchListener()这个方法,因为我现在在代码中找不到这个方法了
    30c78afc928b:我是继承BaseMultiItemQuickAdapter
    30c78afc928b:@猜火车_ 你的版本号是多少?
    _猜火车_:@IceCream_颉 文中所涉及到的我基本都敲过,我刚刚测试了一下,是有这个方法的,没有问题。你确定是的适配器继承了BaseQuickAdapter吗? 还有就是,如果要用下拉刷新,建议别用这个适配器实现。

本文标题:开源框架BaseRecyclerViewAdapterHelpe

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