RecyclerView及与其相关的类

来源:互联网 发布:客户记录软件 编辑:程序博客网 时间:2024/06/17 11:13

常用方法

        getChildAdapterPosition(View):获取view在Adapter中的position。
        getChildLayoutPosition(View):获取view在layout中的position。大部分情况下,它与getChildAdapterPosition()是相同的。但是当新布局尚未完成时(比如新增动画尚未执行完毕时),两者的值是不同的。如下:
if(view != null){    Log.e(TAG,"still adapter.position = "+recyclerView.getChildAdapterPosition(view)+",layout = "+recyclerView.getChildLayoutPosition(view));}view = recyclerView.getChildAt(1);Log.e(TAG,"before adapter.position = "+recyclerView.getChildAdapterPosition(view)+",layout = "+recyclerView.getChildLayoutPosition(view));recyclerView.getAdapter().notifyItemInserted(1);Log.e(TAG,"after adapter.position = "+recyclerView.getChildAdapterPosition(view)+",layout = "+recyclerView.getChildLayoutPosition(view));
        连续调用该方法两次,输出的结果如下:
            //第一次            before adapter.position = 1,layout = 1            after adapter.position = 2,layout = 1            //第二次            still adapter.position = 2,layout = 2            before adapter.position = 1,layout = 1            after adapter.position = 2,layout = 1
        第一次中,after的adapter的pos为2。这是因为我们调用了新insert了一个item,原来的1就被挤到了2,所以adapter.pos就是2。但layout一直没有变化,这是因为insert时有一个动画,在进行第二次输出时,动画没有执行完毕,
所以在layout中该view的pos依旧是1。当第二次调用时,still中可以发现该view的layout.pos已经变成2了,因为新的布局已经生成,在该布局中view的pos就是2。
        getChildCount():获取当前可见的item的数量。注:是可见的item的数量,并不是所有的。

RecyclerView.Adapter

        跟recyclerView关联的Adapter,基本使用略,记得建一个public的ViewHolder即可。
        notifyItemRangeInserted():在指定的开始位置处插入了多个item。
        notifyItemRangeRemoved():从指定的开始位置处移除了多个item。
        notifyItemRangeChanged():从指定的开始位置处有多个item的内容发生了变化,需要进行更新。它有两个方法,多出来的Object对象是传递给观察者的(这些notify内部都是使用了观察者模式)。
        notifyItemRemoved(int):移除指定位置的item。
        notifyItemChanged(int):指定位置的item内容发生了变化。
        notifyItemChanged(int,Object):同上,Object也是传递到相应的观察者中。
        notifyItemInserted(int):在指定的位置处插入一个item。
        notifyItemMoved(int,int):指定位置的两个item进行交换。
        notifyDataSetChanged():与ListView的Adapter类似。它与上面几个方法的区别在于,该方法在增,删,改时不会引起动画的执行,但上面的会。

ItemDecoration

        允许对RecyclerView添加特殊的图案或者使item发生偏移。有以下三个方法:
        onDraw():为RecyclerView添加一些额外的修饰,该方法会在item绘制之前进行调用。也就是说它绘制的内容可能会被item给覆盖住——如果绘制在item的空格处就不会被挡住。
        onDrawOver():基本上与onDraw()类似,只不过在item绘制之后绘制。因此可能会覆盖住item的内容。
        getItemOffsets():获取每一个item的在各个方向的需要额外留出的空余量,各个方向空余量的值需要设置到第一个参数Rect对象中。比如一共有4列,对于720px的手机来说,每一列的宽度为180。如果每一个item的右侧空余量为5px,那么每一列的宽度为175px。

添加分隔线

        主要思路是:每一个item偏移一定的位置,在空出来的位置上绘制图形,这些图形就是分隔线。如下:

public class DividerItemDecor extends RecyclerView.ItemDecoration {    @Override    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {        Paint p = new Paint();        p.setColor(Color.RED);        p.setStyle(Paint.Style.FILL);        final int childCount = parent.getChildCount();        for (int i = 0; i < childCount; i++) {            final View child = parent.getChildAt(i);            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child                    .getLayoutParams();            final int top = child.getBottom() + params.bottomMargin;            final int bottom = top + 5;            c.drawRect(0,top,c.getWidth(),bottom,p);//绘制一个矩形,充当分隔线        }    }    @Override    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {        outRect.set(0,0,0,5);//每一个item的bottom内嵌5px    }}
        上述代码中会出现一个问题:因为getChildCount()返回的是可见item的个数,所以随着不断的滑动同一个item对应的i值会不断变化。因此,如果分隔线的颜色跟i的取值有关的话,就会分隔线不断的变化。如在drawRect()之前添加上如下代码(主要目的是为了让分隔线有两种颜色):
            if(i % 2!=0){                mPaint.setColor(Color.RED);            }else{                mPaint.setColor(Color.YELLOW);            }
        那么,当屏幕滚动时,同个item下的分隔线的颜色会不断切换。为解决该问题,应将i转换成view的adapter.pos。如下:
            int position = parent.getChildAdapterPosition(child);            if(position % 2!=0){                mPaint.setColor(Color.RED);            }else{                mPaint.setColor(Color.YELLOW);            }
        这也是处理不同位置的Item的常用思路:拿到adapter position,再根据这个position进行操作

SortedList

        一个与RecyclerView配套的使用的List集合。它是一个自动对内部元素进行排序的List集合。其常用方法与一般的List集合类似,无非是增删改等,别的方法如下:

        recalculatePositionOfItemAt():重新计算某个位置上item的应该所处的位置。比如某个item被勾选了,它应该出现在最前面等,这个时候就需要重新计算位置。其示例如下:

        @Override        public TodoViewHolder onCreateViewHolder(final ViewGroup parent, int viewType) {            return new TodoViewHolder(                    mLayoutInflater.inflate(R.layout.sorted_list_item_view, parent, false)) {                @Override                void onDoneChanged(boolean isDone) {//这个回调根据具体业务不同而不同,比如点击时的回调等,需要换成自己的回调                    int adapterPosition = getAdapterPosition();//使用adapter position                    if (adapterPosition == RecyclerView.NO_POSITION) {                        return;                    }                    mBoundItem.mIsDone = isDone;                    mData.recalculatePositionOfItemAt(adapterPosition);//通知重新计算位置                }            };        }

        beginBatchedUpdates()endBatchedUpdates():类似于事务,在批量添加或删除之前之后调用。如下:

         mSortedList.beginBatchedUpdates();          try {              mSortedList.add(item1)              mSortedList.add(item2)              mSortedList.remove(item3)             ...         } finally {             mSortedList.endBatchedUpdates();          }

使用方法如下(v7demo):

            mData = new SortedList<Item>(Item.class, new SortedListAdapterCallback<Item>(this) {                @Override                public int compare(Item t0, Item t1) {//对两个item进行比较,用于判断前后位置                    if (t0.mIsDone != t1.mIsDone) {                        return t0.mIsDone ? 1 : -1;                    }                    int txtComp = t0.mText.compareTo(t1.mText);                    if (txtComp != 0) {                        return txtComp;                    }                    if (t0.id < t1.id) {                        return -1;                    } else if (t0.id > t1.id) {                        return 1;                    }                    return 0;                }                @Override                public boolean areContentsTheSame(Item oldItem,                                                  Item newItem) {//两个item的内容是否一样                    return oldItem.mText.equals(newItem.mText);                }                @Override                public boolean areItemsTheSame(Item item1, Item item2) {//两个item是否是同一个。                    return item1.id == item2.id;                }            });
下面以add()为例,分析上面的后两个函数的作用:

    private int add(T item, boolean notify) {        int index = findIndexOf(item, mData, 0, mSize, INSERTION);//二分查找当前item的位置        if (index == INVALID_POSITION) {            index = 0;        } else if (index < mSize) {//如果有            T existing = mData[index];            if (mCallback.areItemsTheSame(existing, item)) {//判断两个item是否一样                if (mCallback.areContentsTheSame(existing, item)) {//判断内容是否一样                    //no change but still replace the item                    mData[index] = item;                    return index;                } else {                    mData[index] = item;                    mCallback.onChanged(index, 1);//通知某个位置上的内容修改了,需要刷新                    return index;                }            }        }        addToData(index, item);//如果没有,就直接将item添加到集合中        if (notify) {            mCallback.onInserted(index, 1);//通过新添加了一个item        }        return index;    }




1 0
原创粉丝点击