1. 程式人生 > >RecyclerView.ItemDecoration實現佔位Item

RecyclerView.ItemDecoration實現佔位Item

RecyclerView.ItemDecoration實現佔位Item

一、為什麼需要佔位Item

神馬筆記的移動功能使用了樹形結構的RecyclerView,在初始狀態下只有一個根Item,點選Item後會展開子目錄內容,為了增加指示性以及豐富介面,因此需要在介面中增加佔位Item。

二、實現效果

空白部分使用了佔位Item,增加了指示性,豐富了介面。

注:原始圖片為720 x 1440,縮放為320 x 640後,空白位置的分割線顯示不是特別明顯。

下載安裝【whatsnote_lastest.apk】能更明顯看到效果。

三、實現原理

使用RecyclerView.ItemDecoration繪製空白部分的分割線產生佔位Item的效果。

關鍵過程:

  1. 獲取最後一個Item的位置,從最後一個Item位置開始繪製分割線
  2. 獲取Item的高度,樹形結構中總有一個根節點,獲取任意一個Item的高度即可
  3. 計算繪製的個數,根據RecyclerView的高度及以上2個引數,即可計算出個數

四、完整程式碼

package club.andnext.recyclerview.decoration;

import
android.content.Context; import android.graphics.Canvas; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.view.View; import androidx.recyclerview.widget.RecyclerView; import club.andnext.recyclerview.R; public class PlaceholderDecoration extends RecyclerView.
ItemDecoration
{ Drawable divider; int margin; Rect bounds; public PlaceholderDecoration(Context context) { this.divider = context.getDrawable(R.drawable.anc_shape_list_divider); this.bounds = new Rect(); } public PlaceholderDecoration setMargin(int value) { this.margin = value; return this; } @Override public void onDraw(Canvas canvas, RecyclerView parent, RecyclerView.State state) { if (parent.getLayoutManager() == null || divider == null) { return; } canvas.save(); final int left; final int right; //noinspection AndroidLintNewApi - NewApi lint fails to handle overrides. if (parent.getClipToPadding()) { left = parent.getPaddingLeft(); right = parent.getWidth() - parent.getPaddingRight(); canvas.clipRect(left, parent.getPaddingTop(), right, parent.getHeight() - parent.getPaddingBottom()); } else { left = 0; right = parent.getWidth(); } int x = left + margin; int y = 0; final int childCount = parent.getChildCount(); for (int i = 0; i < childCount; i++) { final View child = parent.getChildAt(i); parent.getDecoratedBoundsWithMargins(child, bounds); final int bottom = bounds.bottom; y = (y < bottom)? bottom: y; } if (childCount != 0) { int height = parent.getChildAt(0).getHeight(); int count = (parent.getHeight() - y) / height; y += height; for (int i = 0; i < count; i++) { divider.setBounds(x, y, right, y + divider.getIntrinsicHeight()); divider.draw(canvas); y += height; } } canvas.restore(); } }

五、核心程式碼

  1. 計算bottom位置

注意:這裡不能直接取最後一個Item的bottom。 因為是RecyclerView,最後一個Item在位置上不一定是最後一個,並且還存在被重用的情況。

正確的做法是遍歷所有的Item,計算出最大bottom位置。

int y = 0;

final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
    final View child = parent.getChildAt(i);
    parent.getDecoratedBoundsWithMargins(child, bounds);

    final int bottom = bounds.bottom;
    y = (y < bottom)? bottom: y;
}
  1. 繪製分割線

根據RecyclerView的高度及bottom計算出繪製個數,迴圈繪製分割線即可。

if (childCount != 0) {
    int height = parent.getChildAt(0).getHeight();
    int count = (parent.getHeight() - y) / height;

    y += height;
    for (int i = 0; i < count; i++) {
        divider.setBounds(x, y, right, y + divider.getIntrinsicHeight());
        divider.draw(canvas);

        y += height; 
    }
}

六、下載地址

神馬筆記最新版本:【whatsnote_lastest.apk