RecyclerView详解(一)

RecyclerView是什么

从Android 5.0开始,谷歌公司推出了一个用于大量数据展示的新控件RecylerView,可以用来代替传统的ListView,更加强大和灵活。RecyclerView的官方定义如下:

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

RecyclerView是support-v7包中的新组件,是一个强大的滑动组件,与经典的ListView相比,同样拥有item回收复用的功能。

RecyclerView的优点

  • RecyclerView封装了viewholder的回收复用,也就是说RecyclerView标准化了ViewHolder编写Adapter面向的是ViewHolder而不再是View了,复用的逻辑被封装了,写起来更加简单。
    直接省去了listview中convertView.setTag(holder)和convertView.getTag()这些繁琐的步骤。
  • 提供了一种插拔式的体验高度的解耦,异常的灵活,针对一个Item的显示RecyclerView专门抽取出了相应的类,来控制Item的显示,使其的扩展性非常强。
  • 设置布局管理器以控制Item布局方式横向竖向以及瀑布流方式
    例如:你想控制横向或者纵向滑动列表效果可以通过LinearLayoutManager这个类来进行控制(与GridView效果对应的是GridLayoutManager,与瀑布流对应的还StaggeredGridLayoutManager等)。也就是说RecyclerView不再拘泥于ListView的线性展示方式,它也可以实现GridView的效果等多种效果。
  • 可设置Item的间隔样式(可绘制)
    通过继承RecyclerView的ItemDecoration这个类,然后针对自己的业务需求去书写代码。
  • 可以控制Item增删的动画,可以通过ItemAnimator这个类进行控制,当然针对增删的动画,RecyclerView有其自己默认的实现。

 

创建实例

在build.gradle文件中引入该类:

compile 'com.android.support:recycleview-v7:25.0.1'
 private RecyclerView mRecyclerView;
 private RecyclerAdapter mAdapter;
     LinearLayoutManager layoutManager = new LinearLayoutManager(this );
     layoutManager.setOrientation(OrientationHelper.VERTICAL); //设置为垂直布局,这也是默认的
        mRecyclerView.setLayoutManager(layoutManager);//设置布局管理器
        mAdapter = new RecyclerAdapter(this, dataBeanList);//创建适配器
        mRecyclerView.setAdapter(mAdapter);//设置Adapter
        mRecyclerView.setItemAnimator();//设置增加或删除条目的动画
       mRecyclerView.addItemDecoration();//设置分隔线
        //滚动监听
        mAdapter.setOnScrollListener(new RecyclerAdapter.OnScrollListener() {
            @Override
            public void scrollTo(int pos) {
                mRecyclerView.scrollToPosition(pos);
            }
        });

 

布局

创建适配器

标准实现步骤如下:
创建Adapter:创建一个继承RecyclerView.Adapter的Adapter类(VH是ViewHolder的类名)
创建ViewHolder:在Adapter中创建一个继承RecyclerView.ViewHolder的静态内部类,记为VH。

ViewHolder的实现和ListView的ViewHolder实现几乎一样。
③ 在Adapter中实现4个方法

1.onCreateViewHolder()
这个方法主要生成每个Item inflater出一个View,但是该方法返回的是一个ViewHolder。该方法把View直接封装在ViewHolder中,然后我们面向的是ViewHolder这个实例,当然这个ViewHolder需要我们自己去编写。

需要注意的是在onCreateViewHolder()中,映射Layout必须为

view = mInflater.inflate(R.layout.recycleview_item_parent, parent, false);

不能为:view = mInflater.inflate(R.layout.recycleview_item_parent,  null);

2.onBindViewHolder()
这个方法主要用于适配渲染数据到View中。方法提供给你viewHolder而不是原来的convertView。

3.getItemCount()
这个方法就类似于BaseAdapter的getCount方法了,即总共有多少个条目。

4.getItemViewType(int position)

这个方法不是必须实现,前三种必须实现,此方法作用可以根据需求自定义类型在onCreateViewHolderonBindViewHolder做相应处理。如BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType),viewtype即是getItemViewType方法的返回值,onBindViewHolder(BaseViewHolder holder, int position)这个方法可以通过getItemViewType(position)的得到类型并作相应处理。

可以看出,RecyclerView将ListView中getView()的功能拆分成了onCreateViewHolder()onBindViewHolder()

RecyclerView.Adapter代码实现如下:

public class RecyclerAdapter extends RecyclerView.Adapter{
    private Context context;
    private List dataBeanList;
    private LayoutInflater mInflater;
    private OnScrollListener mOnScrollListener;

    public RecyclerAdapter(Context context, List dataBeanList) {
        this.context = context;
        this.dataBeanList = dataBeanList;
        this.mInflater = LayoutInflater.from(context);
    }

    @Override
    public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = null;
        switch (viewType) {
            case DataBean.PARENT_ITEM:
                view = mInflater.inflate(R.layout.recycleview_item_parent, parent, false);
                return new ParentViewHolder(context, view);
            case DataBean.CHILD_ITEM:
                view = mInflater.inflate(R.layout.recycleview_item_child, parent, false);
                return new ChildViewHolder(context, view);
            default:
                view = mInflater.inflate(R.layout.recycleview_item_parent, parent, false);
                return new ParentViewHolder(context, view);
        }
    }

    /**
     * 根据不同的类型绑定View
     *
     * @param holder
     * @param position
     */
    @Override
    public void onBindViewHolder(BaseViewHolder holder, int position) {
        switch (getItemViewType(position)) {
            case DataBean.PARENT_ITEM:
                ParentViewHolder parentViewHolder = (ParentViewHolder) holder;
                parentViewHolder.bindView(dataBeanList.get(position), position, itemClickListener);
                break;
            case DataBean.CHILD_ITEM:
                ChildViewHolder childViewHolder = (ChildViewHolder) holder;
                childViewHolder.bindView(dataBeanList.get(position), position);
                break;
        }
    }

    @Override
    public int getItemCount() {
        return dataBeanList.size();
    }

    @Override
    public int getItemViewType(int position) {
        return dataBeanList.get(position).getType();
    }

    private ItemClickListener itemClickListener = new ItemClickListener() {
        @Override
        public void onExpandChildren(DataBean bean) {
            int position = getCurrentPosition(bean.getID());//确定当前点击的item位置
            DataBean children = getChildDataBean(bean);//获取要展示的子布局数据对象,注意区分onHideChildren方法中的getChildBean()。
            if (children == null) {
                return;
            }
            add(children, position + 1);//在当前的item下方插入
            if (position == dataBeanList.size() - 2 && mOnScrollListener != null) { //如果点击的item为最后一个
                mOnScrollListener.scrollTo(position + 1);//向下滚动,使子布局能够完全展示
            }
        }

        @Override
        public void onHideChildren(DataBean bean) {
            int position = getCurrentPosition(bean.getID());//确定当前点击的item位置
            DataBean children = bean.getChildBean();//获取子布局对象
            if (children == null) {
                return;
            }
            remove(position + 1);//删除
            if (mOnScrollListener != null) {
                mOnScrollListener.scrollTo(position);
            }
        }
    };

    /**
     * 在父布局下方插入一条数据
     *
     * @param bean
     * @param position
     */
    public void add(DataBean bean, int position) {
        dataBeanList.add(position, bean);
        notifyItemInserted(position);
    }

    /**
     * 移除子布局数据
     *
     * @param position
     */
    protected void remove(int position) {
        dataBeanList.remove(position);
        notifyItemRemoved(position);
    }

    /**
     * 确定当前点击的item位置并返回
     *
     * @param uuid
     * @return
     */
    protected int getCurrentPosition(String uuid) {
        for (int i = 0; i < dataBeanList.size(); i++) {
            if (uuid.equalsIgnoreCase(dataBeanList.get(i).getID())) {
                return i;
            }
        }
        return -1;
    }

    /**
     * 封装子布局数据对象并返回
     * 注意,此处只是重新封装一个DataBean对象,为了标注Type为子布局数据,进而展开,展示数据
     * 要和onHideChildren方法里的getChildBean()区分开来
     *
     * @param bean
     * @return
     */
    private DataBean getChildDataBean(DataBean bean) {
        DataBean child = new DataBean();
        child.setType(1);
        child.setParentLeftTxt(bean.getParentLeftTxt());
        child.setChildLeftTxt(bean.getChildLeftTxt());
        child.setChildRightTxt(bean.getChildRightTxt());
        child.setListdata(bean.getListdata());
        return child;
    }

    /**
     * 滚动监听接口
     */
    public interface OnScrollListener {
        void scrollTo(int pos);
    }

    public void setOnScrollListener(OnScrollListener onScrollListener) {
        this.mOnScrollListener = onScrollListener;
    }
}

 

 

BaseViewHolder

public class BaseViewHolder extends RecyclerView.ViewHolder {
    public BaseViewHolder(View itemView) {
        super(itemView);
    }

 

 

你可能感兴趣的:(RecyclerView)