RecyclerView.ItemDecoration


decoration 英文意思:

英[ˌdekəˈreɪʃn] 美[ˌdɛkəˈreʃən] n. 裝飾品; 裝飾,裝潢; 裝飾圖案,裝飾風格; 獎章;

[例句]The decoration and furnishings had to be practical enough for a family home 房子的裝潢和家具都必須很實用,適合家居生活。 [

其他] 復數:decorations

 

RecyclerView.ItemDecoration 裝飾類,都裝飾啥?

RecyclerView.ItemDecoration裝飾的目標當然是RecyclerView里面每個item.

之前ListView有divier屬性可以修改分隔線的樣式

RecyclerView則是提供了

recyclerView.addItemDecoration()

 看一下源碼:

   public static abstract class ItemDecoration {
        /**
         * Draw any appropriate decorations into the Canvas supplied to the RecyclerView.
         * Any content drawn by this method will be drawn before the item views are drawn,
         * and will thus appear underneath the views.
         *
         * @param c Canvas to draw into
         * @param parent RecyclerView this ItemDecoration is drawing into
         * @param state The current state of RecyclerView
         */
        public void onDraw(Canvas c, RecyclerView parent, State state) {
            onDraw(c, parent);
        }

        /**
         * @deprecated
         * Override {@link #onDraw(Canvas, RecyclerView, RecyclerView.State)}
         */
        @Deprecated
        public void onDraw(Canvas c, RecyclerView parent) {
        }

        /**
         * Draw any appropriate decorations into the Canvas supplied to the RecyclerView.
         * Any content drawn by this method will be drawn after the item views are drawn
         * and will thus appear over the views.
         *
         * @param c Canvas to draw into
         * @param parent RecyclerView this ItemDecoration is drawing into
         * @param state The current state of RecyclerView.
         */
        public void onDrawOver(Canvas c, RecyclerView parent, State state) {
            onDrawOver(c, parent);
        }

        /**
         * @deprecated
         * Override {@link #onDrawOver(Canvas, RecyclerView, RecyclerView.State)}
         */
        @Deprecated
        public void onDrawOver(Canvas c, RecyclerView parent) {
        }


        /**
         * @deprecated
         * Use {@link #getItemOffsets(Rect, View, RecyclerView, State)}
         */
        @Deprecated
        public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {
            outRect.set(0, 0, 0, 0);
        }

        /**
         * Retrieve any offsets for the given item. Each field of <code>outRect</code> specifies
         * the number of pixels that the item view should be inset by, similar to padding or margin.
         * The default implementation sets the bounds of outRect to 0 and returns.
         *
         * <p>
         * If this ItemDecoration does not affect the positioning of item views, it should set
         * all four fields of <code>outRect</code> (left, top, right, bottom) to zero
         * before returning.
         *
         * <p>
         * If you need to access Adapter for additional data, you can call
         * {@link RecyclerView#getChildAdapterPosition(View)} to get the adapter position of the
         * View.
         *
         * @param outRect Rect to receive the output.
         * @param view    The child view to decorate
         * @param parent  RecyclerView this ItemDecoration is decorating
         * @param state   The current state of RecyclerView.
         */
        public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state) {
            getItemOffsets(outRect, ((LayoutParams) view.getLayoutParams()).getViewLayoutPosition(),
                    parent);
        }
    }
View Code

會發現主要有下面三個方法:

public void onDraw(Canvas c, RecyclerView parent, State state)
public void onDrawOver(Canvas c, RecyclerView parent, State state)
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state)
 
那來看看都什么意思干么用:
直接看注釋吧
onDraw():
/**
* Draw any appropriate decorations into the Canvas supplied to the RecyclerView.
* Any content drawn by this method will be drawn before the item views are drawn, * and will thus appear underneath the views. *
* @param c Canvas to draw into * @param parent RecyclerView this ItemDecoration is drawing into * @param state The current state of RecyclerView */  

大概是說會在item畫之前畫些東西,會現在Item下面。那相當於是一個背景。

 onDrawOver()

  /**
         * Draw any appropriate decorations into the Canvas supplied to the RecyclerView.
         * Any content drawn by this method will be drawn after the item views are drawn
         * and will thus appear over the views.
         *
         * @param c Canvas to draw into
         * @param parent RecyclerView this ItemDecoration is drawing into
         * @param state The current state of RecyclerView.
         */
        public void onDrawOver(Canvas c, RecyclerView parent, State state) {
            onDrawOver(c, parent);
        }
will be drawn after the item views are drawn and will thus appear over the views.
很明白與上面的相對,會有Item畫完之后去畫,在浮在item內容上面。

getItemOffsets()
 /**
         * Retrieve any offsets for the given item. Each field of <code>outRect</code> specifies
         * the number of pixels that the item view should be inset by, similar to padding or margin.
         * The default implementation sets the bounds of outRect to 0 and returns.
         *
         * <p>
         * If this ItemDecoration does not affect the positioning of item views, it should set
         * all four fields of <code>outRect</code> (left, top, right, bottom) to zero
         * before returning.
         *
         * <p>
         * If you need to access Adapter for additional data, you can call
         * {@link RecyclerView#getChildAdapterPosition(View)} to get the adapter position of the
         * View.
         *
         * @param outRect Rect to receive the output.
         * @param view    The child view to decorate
         * @param parent  RecyclerView this ItemDecoration is decorating
         * @param state   The current state of RecyclerView.
         */
        public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state) {
            getItemOffsets(outRect, ((LayoutParams) view.getLayoutParams()).getViewLayoutPosition(),
                    parent);
        }

也說得很明白:similar to padding or margin.跟padding margin相似。給設置邊距的。

從getItemOffsets()來開始實踐

我們給recyclerview 加上背景以便觀察。

<android.support.v7.widget.RecyclerView
android:id="@+id/rcv_qulitry"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#f00">
</android.support.v7.widget.RecyclerView>

實現在自義定的decoration類

package com.lechang.fragment.decoration;

import android.graphics.Rect;
import android.support.v7.widget.RecyclerView;
import android.view.View;

/**
 * Created by hongtao on 2017/11/17.
 */

public class MyDecoration extends RecyclerView.ItemDecoration {

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        outRect.left = 5;
        outRect.right = 5;
        outRect.bottom = 10;
        super.getItemOffsets(outRect, view, parent, state);
    }
}

馬上來用

recyclerView.addItemDecoration(new MyDecoration());

看看效果,嘿嘿,尼瑪不是那么回事,怎么不起作用呢?

蒙逼了?

仔細看一下代碼,方法調用了super.getItemOffsets(outRect, view, parent, state);再點進去看,

public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state) {
getItemOffsets(outRect, ((LayoutParams) view.getLayoutParams()).getViewLayoutPosition(),
parent);
}
然后再調用了
@Deprecated
public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {
outRect.set(0, 0, 0, 0);
}

看到沒

outRect.set(0, 0, 0, 0);

給設置成0了。

那我們

       outRect.left = 5; outRect.right = 5; outRect.bottom = 10;

設置的值就成白做了。

所以得把這個賦值放到super之后。

package com.lechang.fragment.decoration;

import android.graphics.Rect;
import android.support.v7.widget.RecyclerView;
import android.view.View;

/**
 * Created by hongtao on 2017/11/17.
 */

public class MyDecoration extends RecyclerView.ItemDecoration {

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        super.getItemOffsets(outRect, view, parent, state);
        //切記要先調super.
        outRect.left = 5;
        outRect.right = 5;
        outRect.bottom = 10;
    }
}

 

這回可以了。
看一下效果:

紅色底出來了。相當於padding .

只是底紅露出,不能當分隔線,你非要用也行。

主要的還是要用ondraw把分隔線畫出來。

下面來試ondraw().

原型:如下 

public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state)

這是一個回調的方法,給了一個畫布,RecyclerView ,和RecyclerView.State

RecyclerView.State:給了下面三個狀態
static final int STEP_START = 1;
static final int STEP_LAYOUT = 1 << 1;
static final int STEP_ANIMATIONS = 1 << 2;

意思是我們可以在這三個不同時期做不同的事,畫不同的東西。有需求可以安排。

 

 RecyclerView parent

既然是parent 那他的child都是個個item.

那整個方法的意思就是用Canvas c給每個item都畫上裝飾(分隔線)。

來一段代碼:

package com.lechang.fragment.decoration;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.support.v7.widget.RecyclerView;
import android.view.View;

/**
 * Created by hongtao on 2017/11/17.
 */

public class MyDecoration extends RecyclerView.ItemDecoration {

    Paint dividerPaint;
    int dividerHeight = 3;

    public MyDecoration(Context context, int dividerHeight) {
        dividerPaint = new Paint();
        dividerPaint.setColor(Color.BLACK);
        this.dividerHeight = dividerHeight;
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        super.getItemOffsets(outRect, view, parent, state);
        //切記要先調super.
//        outRect.left = 5;
//        outRect.right = 5;
        outRect.bottom = 20;
    }

    @Override
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
        int childCount = parent.getChildCount();
        int left = parent.getPaddingLeft();
        int right = parent.getWidth() - parent.getPaddingRight();

        for (int i = 0; i < childCount - 1; i++) {
            View view = parent.getChildAt(i);
            float top = view.getBottom();
            float bottom = view.getBottom() + dividerHeight;
            //畫了一個矩型
            c.drawRect(left, top, right, bottom, dividerPaint);
        }
    }
}

 

outRect.bottom 給了 20的值,要是不給這個值,那將什么也看不到。因為是在item下層的;
最終效果:黑色線是onDraw結果,紅是底

 




接下來看:
onDrawOver()方法效果

 

package com.lechang.fragment.decoration;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.support.v7.widget.RecyclerView;
import android.view.View;

/**
 * Created by hongtao on 2017/11/17.
 */

public class MyDecoration extends RecyclerView.ItemDecoration {

    Paint dividerPaint;
    int dividerHeight = 3;

    public MyDecoration(Context context, int dividerHeight) {
        dividerPaint = new Paint();
        dividerPaint.setColor(Color.BLACK);
        this.dividerHeight = dividerHeight;
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        super.getItemOffsets(outRect, view, parent, state);
        //切記要先調super.
//        outRect.left = 5;
//        outRect.right = 5;
//        outRect.bottom = 20;
    }

    @Override
    public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
        int childCount = parent.getChildCount();
        int left = parent.getPaddingLeft();
        int right = parent.getWidth() - parent.getPaddingRight();

        for (int i = 0; i < childCount - 1; i++) {
            View view = parent.getChildAt(i);
            float top = view.getBottom();
            float bottom = view.getBottom() + dividerHeight;
            //畫了一個矩型
            c.drawRect(left, top, right, bottom, dividerPaint);
        }
    }

    @Override
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
        int childCount = parent.getChildCount();
        int left = parent.getPaddingLeft();
        int right = parent.getWidth() - parent.getPaddingRight();

        for (int i = 0; i < childCount - 1; i++) {
            View view = parent.getChildAt(i);
            float top = view.getBottom();
            float bottom = view.getBottom() + dividerHeight;
            //畫了一個矩型
            c.drawRect(left, top, right, bottom, dividerPaint);
        }
    }
}

 

 

drawOver在上層畫,所以不需要getItemOffsets配合。

 至此,ImtemDecoration這個類基本我們就會用了。

如果對Item位置做一些邏輯處理,還能做出一些有意思的東西。接下來再寫。告一段落。

 

 
       


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM