RecycleView简单使用

来源:互联网 发布:淘宝号不要了怎么注销 编辑:程序博客网 时间:2024/06/15 22:56

  • 简介
  • 基本使用流程
    • 导包
    • 设置布局管理器
    • 设置Adapter
    • 添加分割线
    • 设置动画
    • 点击事件
    • HeadView FootView
  • 复杂布局层数简化
    • 布局要求
    • 布局解析
    • 布局实现
    • 最终效果展示

简介

A flexible view for providing a limited window into a large data set.

一个展示大量数据、灵活的View控件。

个人理解为ListView、GridView的官方升级版本,将ViewHolder、复用itemView等ListView优化方案吸收,更加灵活、解耦的展示大量数据。

2017.11.20 增加推荐点击事件处理、HeadView+FootView的封装.

基本使用流程

1.导包

使用RecycleView需要引入v7包对应。

// 版本号跟v7包版本号一致就行compile 'com.android.support:recyclerview-v7:xx.x.x'

2.设置布局管理器

RecycleView.setLayoutManager(LayoutManager);

自带的三个布局管理器:

StaggeredGridLayoutManager : 流式布局管理器

A LayoutManager that lays out children in a staggered grid formation.
It supports horizontal & vertical layout as well as an ability to layout children in reverse..

以交错网格的形式布局,支持水平和垂直布局,同时支持反向。

LinearLayoutManager:线性布局管理器

similar functionality to {@link android.widget.ListView}

官方解释:功能和ListView类似。。。

GridLayoutManager:表格布局管理器

By default, each item occupies 1 span. You can change it by providing a custom
{@link SpanSizeLookup} instance via {@link #setSpanSizeLookup(SpanSizeLookup)}.

默认每个Item占据一个跨度(span:表格的列数既定之后,每个item的宽度),但是你可以setSpanSizeLookup()方法修改每个item的跨度。

功能类似于GridView,继承了LinearLayoutManager,但是官方的解释上面是重点,通过上面的功能能够实现更加灵活的表格布局,将往常只能嵌套使用的布局在不嵌套的情况展示。

3.设置Adapter

RecycleView.setAdapter();

adapter必须重写方法如下:

new RecyclerView.Adapter() {    /**     * 根据viewType返回想要的ViewHolder,强行绑定ListView中ViewHolder模式。     *     * 每个Item都会调用仅且调用一次,即每个Item的ViewHolder对象都不被其他Item(即使类型相同)复用。     * 这里与ListView使用ViewHolder有所区别。     *     * 当Item需要被复用,调用方法{@link #onBindViewHolder(RecyclerView.ViewHolder, int)}     */    @Override    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item1, parent, false);        RecyclerViewAdapter1.ViewHolder viewHolder = new RecyclerViewAdapter1.ViewHolder(view);        return viewHolder;    }    /**     * 根据加载位置进行数据展示     * 当Item被展示到屏幕上时调用,进行Item展示、更新     */    @Override    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {    }    /**     * 返回总的Item数量     */    @Override    public int getItemCount() {        return 0;    }});

4. 添加分割线

RecycleView.addItemDecoration(RecyclerView.ItemDecoration);

以前添加分割线的方法不再有效。

android:divider="#ff0000"android:dividerHeight="1dp"

自定义分割线

new RecyclerView.ItemDecoration() {    /**     * 调用在绘制Item之前     * 一般情况两个Draw方法选一个重写即可     */    @Override    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {    }    /**     * 调用在绘制Item之后     */    @Override    public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {    }    /**     * 设置偏移量     */    @Override    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {        // 对Item进行偏移        outRect.set(0,0,0,8);    }});

5. 设置动画

RecyclerView.setItemAnimator(new DefaultItemAnimator());

这里使用默认的系统动画。

同时调用如下方法进行Item的add和remove:

public void addItem(int position, String s){    arrayList.add(position,s);    notifyItemInserted(position);}public void remove(int position){    arrayList.remove(position);    notifyItemRemoved(position);}

6.点击事件

方式一:由于RecycleView没有直接给出点击事件的接口,可以将事件监听接口放到Adapter中,在布局容器进行实现,容器中调用就好了,这里不做实现。

方式二(推荐使用):RxJava PublishSubject实现监听事件的传递。

没有使用RxJava不能使用!!!

adapter实现:

private final PublishSubject<Model> onClickSubject = PublishSubject.create();/*** 点击事件 进行订阅** @author fengzhen* @version v6.3.0, 2017/11/18 17:43*/public PublishSubject<Model> getOnClickSubject() {   return onClickSubject;}@Overridepublic void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {    Model model = mListData.get(position);    ViewHolder viewHolder = (ViewHolder) holder;    viewHolder.mTvContent.setOnClickListener(v -> onClickSubject.onNext(model));}

外部订阅:

mXXXAdapter.getOnClickSubject().subscribe(new DefaultSubscriber<Model>() {            @Override            public void onNext(Modeldata) {                // 点击事件处理                showShortToast(data.getString());            }        });

好,就酱!

7.HeadView + FootView

从ListView到RecyclerView怎么能把很常用的HeadView、FootView给忘了。
这里直接贴封装的一个简单Adapter,使用直接继承My Adapter 就可以直接用了。

import android.support.v7.widget.RecyclerView;import android.view.View;import android.view.ViewGroup;/** * 扩展RecyclerView.Adapter * 添加HeadView、FootView * * @author fengzhen * @version v6.3.0, 2017/11/20 */public abstract class RecyclerViewExtendAdapter extends RecyclerView.Adapter {    public static final int ITEM_TYPE_HEADVIEW = 999;    public static final int ITEM_TYPE_FOOTVIEW = 998;    private View mHeadview;    private View mFootview;    private boolean hasHeadView = false;    public void setHeadview(View headview) {        hasHeadView = headview != null;        this.mHeadview = headview;        notifyDataSetChanged();    }    public void setFootview(View footview) {        this.mFootview = footview;        notifyDataSetChanged();    }    public View getmHeadview() {        return mHeadview;    }    public View getmFootview() {        return mFootview;    }    /**     * 不可重写,     * 重写方法{@link RecyclerViewExtendAdapter#getNormalItemViewType}实现具体子类操作     *     * @author fengzhen     * @version v6.3.0, 2017/11/20 15:57     */    @Override    public final int getItemViewType(int position) {        if (mHeadview != null && position < 1) {            return ITEM_TYPE_HEADVIEW;        } else if (mFootview != null && position == getItemCount() - 1) {            return ITEM_TYPE_FOOTVIEW;        } else {            return getNormalItemViewType(hasHeadView ? position - 1 : position);        }    }    /**     * 子类实现此方法,等同于直接实现{@link RecyclerView.Adapter#getItemViewType(int)} ()}     *     * @return The view type of this ViewHolder.     * @author fengzhen     * @version v6.3.0, 2017/11/20 15:52     */    protected int getNormalItemViewType(int position) {        return super.getItemViewType(position);    }    /**     * 不可重写     * 子类实现{@link RecyclerViewExtendAdapter#getNormalItemCount()}     *     * @author fengzhen     * @version v6.3.0, 2017/11/20 16:10     */    @Override    public final int getItemCount() {        return getNormalItemCount() + (mHeadview == null ? 0 : 1) + (mFootview == null ? 0 : 1);    }    /**     * 子类实现此方法,等同于实现{@link RecyclerView.Adapter#getItemCount()}     *     * @author fengzhen     * @version v6.3.0, 2017/11/20 16:06     */    protected abstract int getNormalItemCount();    /**     * 不可重写     * 子类实现{@link RecyclerViewExtendAdapter#onNormalCreateViewHolder(ViewGroup, int)}     *     * @author fengzhen     * @version v6.3.0, 2017/11/20 16:10     */    @Override    public final RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {        switch (viewType) {            case ITEM_TYPE_HEADVIEW:                return new HeadViewHolder(mHeadview);            case ITEM_TYPE_FOOTVIEW:                return new FootViewHolder(mFootview);            default:                return onNormalCreateViewHolder(parent, viewType);        }    }    /**     * 子类实现此方法,等同于实现{@link RecyclerView.Adapter#onCreateViewHolder(ViewGroup, int)}     *     * @author fengzhen     * @version v6.3.0, 2017/11/20 16:06     */    protected abstract RecyclerView.ViewHolder onNormalCreateViewHolder(ViewGroup parent, int viewType);    /**     * 不可重写     * 子类实现{@link RecyclerViewExtendAdapter#onNormalBindViewHolder(RecyclerView.ViewHolder, int, int)}     *     * @author fengzhen     * @version v6.3.0, 2017/11/20 16:10     */    @Override    public final void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {        int itemViewType = getItemViewType(position);        switch (itemViewType) {            case ITEM_TYPE_HEADVIEW:            case ITEM_TYPE_FOOTVIEW:                break;            default:                onNormalBindViewHolder(holder, hasHeadView ? position - 1 : position, itemViewType);                break;        }    }    /**     * 子类实现此方法,等同于实现{@link RecyclerView.Adapter#onBindViewHolder(RecyclerView.ViewHolder, int)}     *     * @author fengzhen     * @version v6.3.0, 2017/11/20 16:06     */    protected abstract void onNormalBindViewHolder(RecyclerView.ViewHolder holder, int position, int itemViewType);    private class HeadViewHolder extends RecyclerView.ViewHolder {        public HeadViewHolder(View itemView) {            super(itemView);        }    }    private class FootViewHolder extends RecyclerView.ViewHolder {        public FootViewHolder(View view) {            super(view);        }    }}

复杂布局层数简化

1. 布局要求

实现如下的布局:

布局要求

2. 布局解析

实现方式一: 直接硬布局,最外层用一个ScrollView,里面用 TextView + ListView + TextView + GridView。还需要对ListView和GridView进行重写测量方法,才能实现效果。

实现方式二: 整个作为一个ListView,Title、ListView 、GridView都看成是父ListView 的一个Item。但是对于其中的交互逻辑的代码不要控制,写出来肯定很不“优美”。

实现方式三: 使用RecycleView的GridLayoutManager布局,通过item type 设置,将Title、ListVite item和GridView item都作为RecycleView 的item,使用一层布局,这也是推荐的做法。

3. 布局实现

实现布局的重点在于GridLayoutManager的setSpanSizeLookup()方法。

设置布局管理器:

// 设置布局管理器private void initLayout() {    // 这里的4,取所需列数的最小公倍数    mRecyclerView1.setLayoutManager(new GridLayoutManager(this, 4));}

Adapter实现:

/** * Created by fengzhen. *  * recyclerView 适配器 */public class RecyclerViewAdapter1 extends RecyclerView.Adapter<RecyclerViewAdapter1.ViewHolder> {    // 布局类型    public static final int TITLE_1 = 0x0;    public static final int TITLE_2 = 0x1;    public static final int LINEAR_1 = 0x2;    public static final int GRID_2 = 0x3;    // 数据集    private List<String> arrayList;    public RecyclerViewAdapter1(List<String> list) {        arrayList = list;    }    /**     * 查找item布局,强制绑定ViewHolder     */    @Override    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {        // 没做类型判定 需要时判断 viewType        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item1, parent, false);        return new ViewHolder(view);    }    /**     * 根据加载位置进行数据展示     */    @Override    public void onBindViewHolder(ViewHolder holder, int position) {        // 没做类型判定 需要时判断 viewType        holder.textView1.setText(arrayList.get(position));    }    /**     * 实现布局的重点     */    @Override    public void onAttachedToRecyclerView(RecyclerView recyclerView) {        super.onAttachedToRecyclerView(recyclerView);        /**         * 处理GridLayoutManager布局         * LayoutManager列数设置为 所有可能出现的列数的最小公倍数         * 具体的列数,返回在总列数的比例         *  例:可能出现的列数有:  1、3、4、7         *      LayoutManager的列数设置为 : 1*3*4*7 = 84;         *      对应列数的返回值: 84、 28、21、12;         */        RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();        if(manager instanceof GridLayoutManager) {            final GridLayoutManager gridManager = ((GridLayoutManager) manager);            gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {                @Override                public int getSpanSize(int position) {                    int type = getItemViewType(position);                    switch (type){                        case TITLE_1:                        case TITLE_2:                            return 4;                        case LINEAR_1:                            return 1;                        case GRID_2:                            return 2;                        default:                            return 4;                    }                }            });        }    }    /**     * 返回不同的类型     *     * @author fengzhen     * @version v1.0, 2017/8/23 15:47     */    @Override    public int getItemViewType(int position) {        if (position == 0) {            return TITLE_1;        } else if (position < 8) {            return LINEAR_1;        } else if (position == 8) {            return TITLE_2;        } else {            return GRID_2;        }    }    /**     * 类似listview中的方法,获取总item数     */    @Override    public int getItemCount() {        return arrayList.size();    }    /**     * 继承RecycleView的ViewHolder,对item控件进行初始化     */    public static class ViewHolder extends RecyclerView.ViewHolder {        public TextView textView1;        public ViewHolder(View itemView) {            super(itemView);            textView1 = (TextView) itemView.findViewById(R.id.textView1);        }    }}

4. 最终效果展示

最终效果

原创粉丝点击