Android收藏集AndroidAndroid技术

开源框架BaseRecyclerViewAdapterHelpe

2017-08-14  本文已影响21852人  _猜火车_

前言

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

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

一、框架引入

    allprojects {
        repositories {
            ...
            maven { url "https://jitpack.io" }
        }
    }
    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 常用示例代码

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

<?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>
<?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>
public class Model {
    private String title;
    private String content;
    private String imgUrl;

    //生成set、get方法
    ......
}
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();
    }
}
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);
    }
}

三、点击事件

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;
            }
        });
注意事项

3.2 条目子控件事件

Item子控件的点击事件

    @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子控件的长按事件

    @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;
            }
        });
注意事项

多个Item子控件事件

 @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();
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);
adapter.setNotDoAnimationCount(count);

由于进入界面的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);
mQuickAdapter.removeHeaderView(headerView);
mQuickAdapter.removeFooterView(footerView);
mQuickAdapter.removeAllHeaderView();
mQuickAdapter.removeAllFooterView();
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);

八、分组布局

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

    public MySection(Video t) {
        super(t);
    }
}
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的方式

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;
    }
}
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;
        }
    }

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

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

第一步:创建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 设置代理的方式

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;
            }
        }
    }
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);
    }
}

十、设置空布局

// 没有数据的时候默认显示该布局
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) {}
};
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);
    }
}
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);

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

十三、自定义ViewHolder

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

十三、扩展框架

结束语

上一篇 下一篇

猜你喜欢

热点阅读