Android进阶——万能的RecycleView详解(一)

引言

自RecyclerView面世以来,就被认为是作为ListView和GridView控件的替代者,在最新的support-V7版本中提供支持。RecyclerView的强大已经不需要再多的语言去赞美了。

一、RecyclerView概述

RecyclerView继承自ViewGroup,而不是与ListView、GridView是AdapterView的子类,它是一种新的视图组,目标是为任何基于适配器的视图提供相似的渲染方式。具有极高的扩展性,因此用它可以创建想到的任何种类的的布局,ListView、GirdView还有瀑布流式布局,能够在布局的计算过程中检测批量数据集的变化。从而跟踪适配器的变化来计算动画保存的LayoutManager。它还避免不必要的绑定来提高性能。
《Android进阶——万能的RecycleView详解(一)》

二、RecyclerView中的重要角色

1、RecyclerView.Adapter

RecyclerView.Adapter<VH extends RecyclerView.ViewHolder>

RecyclerView使用的是全新的适配器。与AdapterView使用的适配器类似,但也略有不同,比如RecyclerView必须使用标准化ViewHolder。使用时需要重写两个主要方法onCreateViewHolder和onBindViewHolder:分别用来展现视图和它的持有者和把数据绑定到视图上。这样设计的优势在于只有当我们真正需要去创建一个新视图才会调用onCreateViewHolder,不需要去检查它是否已被回收,然后再与数据绑定。


//一个基本的Adapter结构
public class TrainingAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        //创建Item的视图
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        //绑定数据
    }

    @Override
    public int getItemCount() {
        return 0;
    }

    class TrainingViewHolder extends RecyclerView.ViewHolder{

        public TrainingViewHolder(View itemView) {
            super(itemView);
        }
    }
}

与AdapterView使用的适配器不同,默认的实现中RecyclerView没有实现onItemClickListener和onItemLongClickListener事件,在实际的开发中需要我们自己去实现,可以通过回调或者监听onTouch,一般选择回调方式。最后一点不同的是更新RecyclerView时,从适配器上添加或移除条目时增加了notifyItemInserted(position)和notifyItemRemoved(position)可明确通知适配器,而不是简单调用notifyDataSetChanged(),当然也可以直接notifyDataSetChanged()。

2、RecyclerView.LayoutManager

RecyclerView.LayoutManager相当于是充当一个管家的功能,负责itemview的测量和布局、滚动和重用,还决定何时回收不再可见的itemview,只需要通过改变RecyclerView的LayoutManager(当然相应的item布局得稍微调整下还有分割线),可以实现垂直滚动列表(LinearLayoutManager)、网格水平滚动列表(GridLayoutManager)和瀑布流式布局(StaggeredGridLayoutManager)。

  • LinearLayoutManager
 LinearLayoutManager layoutManager = new LinearLayoutManager(this);
 layoutManager.setOrientation(LinearLayoutManager.VERTICAL);//LinearLayoutManager.HORIZONTAL
  • GridLayoutManager
GridLayoutManager layoutManager =new GridLayoutManager (this,3);
  • StaggeredGridLayoutManager
    上面的item布局我们使用了固定的高度,要使用瀑布流式布局,我们还得在适配器的onBindViewHolder方法中为我们的item设置相应的高度即可。

3、RecyclerView.ItemAnimator

当适配器改变时候,运行的插入或删除时候,会自动显示对应的动画效果,目前系统只实现了一个DefaultItemAnimator,开发中也可以使用github上开源的第三方类库来实现更加酷炫的效果

4、RecyclerView.ItemDecoration

主要用于定制Item之间的分割线(是通过绘制的),当我们调用mRecyclerView.addItemDecoration()方法添加decoration的时候,RecyclerView在创建时候就去绘制decorator(即调用该类的onDraw和onDrawOver方法),获取到listDivider以后,该属性的值是个Drawable,在getItemOffsets中,outRect去设置了绘制的范围,最后在onDraw中实现了真正的绘制。(万能的RecycleView分割线以下贴一个来自于网上的ItemDecoration实现类)

  • onDraw方法先于drawChildren执行
  • onDrawOver在drawChildren之后,通常只需要复写其中一个即可。
  • getItemOffsets 可以通过outRect.set()为每个Item设置一定的偏移量,主要用于绘制Decorator。
/** *使用方法: 添加默认分割线:高度为2px,颜色为灰色 mRecyclerView.addItemDecoration(new RecycleViewDivider(mContext, LinearLayoutManager.VERTICAL)); 添加自定义分割线:可自定义分割线drawable mRecyclerView.addItemDecoration(new RecycleViewDivider( mContext, LinearLayoutManager.VERTICAL, R.drawable.divider_mileage)); 添加自定义分割线:可自定义分割线高度和颜色 mRecyclerView.addItemDecoration(new RecycleViewDivider( mContext, LinearLayoutManager.VERTICAL, 10, getResources().getColor(R.color.divide_gray_color))); * */
public class RecycleViewDivider extends RecyclerView.ItemDecoration {

    private Paint mPaint;
    private Drawable mDivider;
    private int mDividerHeight = 2;//分割线高度,默认为1px
    private int mOrientation;//列表的方向:LinearLayoutManager.VERTICAL或LinearLayoutManager.HORIZONTAL
    private static final int[] ATTRS = new int[]{android.R.attr.listDivider};

    /** * 默认分割线:高度为2px,颜色为灰色 * * @param context * @param orientation 列表方向 */
    public RecycleViewDivider(Context context, int orientation) {
        if (orientation != LinearLayoutManager.VERTICAL && orientation != LinearLayoutManager.HORIZONTAL) {
            throw new IllegalArgumentException("请输入正确的参数!");
        }
        mOrientation = orientation;

        final TypedArray a = context.obtainStyledAttributes(ATTRS);
        mDivider = a.getDrawable(0);
        a.recycle();
    }

    /** * 自定义分割线 * * @param context * @param orientation 列表方向 * @param drawableId 分割线图片 */
    public RecycleViewDivider(Context context, int orientation, int drawableId) {
        this(context, orientation);
        mDivider = ContextCompat.getDrawable(context, drawableId);
        mDividerHeight = mDivider.getIntrinsicHeight();
    }

    /** * 自定义分割线 * * @param context * @param orientation 列表方向 * @param dividerHeight 分割线高度 * @param dividerColor 分割线颜色 */
    public RecycleViewDivider(Context context, int orientation, int dividerHeight, int dividerColor) {
        this(context, orientation);
        mDividerHeight = dividerHeight;
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setColor(dividerColor);
        mPaint.setStyle(Paint.Style.FILL);
    }


    //获取分割线尺寸
    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        super.getItemOffsets(outRect, view, parent, state);
        outRect.set(0, 0, 0, mDividerHeight);
    }

    //绘制分割线
    @Override
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
        super.onDraw(c, parent, state);
        if (mOrientation == LinearLayoutManager.VERTICAL) {
            drawVertical(c, parent);
        } else {
            drawHorizontal(c, parent);
        }
    }

    //绘制横向 item 分割线
    private void drawHorizontal(Canvas canvas, RecyclerView parent) {
        final int left = parent.getPaddingLeft();
        final int right = parent.getMeasuredWidth() - parent.getPaddingRight();
        final int childSize = parent.getChildCount();
        for (int i = 0; i < childSize; i++) {
            final View child = parent.getChildAt(i);
            RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) child.getLayoutParams();
            final int top = child.getBottom() + layoutParams.bottomMargin;
            final int bottom = top + mDividerHeight;
            if (mDivider != null) {
                mDivider.setBounds(left, top, right, bottom);
                mDivider.draw(canvas);
            }
            if (mPaint != null) {
                canvas.drawRect(left, top, right, bottom, mPaint);
            }
        }
    }

    //绘制纵向 item 分割线
    private void drawVertical(Canvas canvas, RecyclerView parent) {
        final int top = parent.getPaddingTop();
        final int bottom = parent.getMeasuredHeight() - parent.getPaddingBottom();
        final int childSize = parent.getChildCount();
        for (int i = 0; i < childSize; i++) {
            final View child = parent.getChildAt(i);
            RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) child.getLayoutParams();
            final int left = child.getRight() + layoutParams.rightMargin;
            final int right = left + mDividerHeight;
            if (mDivider != null) {
                mDivider.setBounds(left, top, right, bottom);
                mDivider.draw(canvas);
            }
            if (mPaint != null) {
                canvas.drawRect(left, top, right, bottom, mPaint);
            }
        }
    }
}

三、RecycleView常用的方法

方法说明
void addItemDecoration(RecyclerView.ItemDecoration decor)添加item分割线
void addOnItemTouchListener(RecyclerView.OnItemTouchListener listener)添加item ontouch监听
void addOnScrollListener(RecyclerView.OnScrollListener listener)添加 scroll监听
RecyclerView.ViewHolder findContainingViewHolder(View view)获取当前view的ViewHolder
RecyclerView.ViewHolder findViewHolderForAdapterPosition(int position)获取当前position对应的ViewHolder
void setAdapter(Adapter adapter)设置Adapter
void swapAdapter(Adapter adapter, boolean removeAndRecycleExistingViews)快速替换adapter

四、RecycleView的使用

下篇Android进阶——RecycleView的使用之自定义单选列表(二) Android进阶——RecycleView的使用之自定义聊天界面(三)见。Orz~~

    原文作者:CrazyMo_
    原文地址: https://blog.csdn.net/CrazyMo_/article/details/52691305
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞