溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Android RecyclerView區(qū)分視圖類型的Divider的實(shí)現(xiàn)

發(fā)布時(shí)間:2020-09-29 07:12:55 來源:腳本之家 閱讀:207 作者:林空鹿飲 欄目:移動(dòng)開發(fā)

我們都知道support庫(kù)有一個(gè)DividerItemDecoration, 可以作為Item之間的分隔線(divider)。但它作用以后所有的item之間都會(huì)有這個(gè)分隔線,實(shí)際情況往往是:recyclerView中存在多種的視圖類型(viewType), 我們只是需要在某一類型的視圖后添加分隔線。

要實(shí)現(xiàn)這種分隔線效果并不是什么難事,既然是某一類型有這個(gè)分隔線,那在直接在這種視圖的layout文件上增加如下一個(gè)bottomLine界面元素妥妥的:

<View
  android:layout_width="match_parent"
  android:layout_height="0.5dp"
  android:background="@color/colorGrayLight" />

但如果添加這樣一個(gè)界面元素導(dǎo)致新增一層布局那感覺代價(jià)有點(diǎn)大。另外一種情況,如果當(dāng)前這個(gè)視圖由于某種原因存在padding,而期望的分隔線是穿透整個(gè)布局的,那添加bottomLine的做法也是行不通的;還有一種情況同一類型布局在一個(gè)頁(yè)面有分隔線,在另一個(gè)頁(yè)面沒有分隔線;總之就是希望分隔線和視圖內(nèi)容無關(guān)。所以我們需要一種類似DividerItemDecoration的decoration,它能針對(duì)某些viewType起作用。

先要了解一下RecyclerView.ItemDecoration,它有2個(gè)重要的回調(diào)方法:onDrawOver和getItemOffsets。onDrawOver其實(shí)是一種應(yīng)用多個(gè)item的方法,所以無論如何都需要一個(gè)遍歷操作。需要理解的是getItemOffsets中outRect這個(gè)輸出型參數(shù),雖然是一個(gè)Rect類型,但并不表示任何范圍,而只是一個(gè)item四周的間隔距離:

Android RecyclerView區(qū)分視圖類型的Divider的實(shí)現(xiàn)

outRect參數(shù)各域的含義

我們思路已經(jīng)很清楚了: 在getItemOffsets中判斷當(dāng)前view的類型(parent.getChildViewHolder(view)), 如果是我們需要的類型設(shè)置對(duì)應(yīng)的bottom;在onDrawOver中我們遍歷recyclerView的child,同樣如果是我們需要的類型將分隔線畫在對(duì)應(yīng)位置上就行了;這個(gè)decoration可以針對(duì)任意一種或者幾種類型設(shè)置不種的drawable,我們當(dāng)前用SparseArray存儲(chǔ),key就是視圖的viewType
private final SparseArrayCompat<Drawable> mDividers = new SparseArrayCompat<>(2);
同時(shí)我們可以設(shè)置這個(gè)item的高度,當(dāng)Drawable為null時(shí)相當(dāng)于一個(gè)透明的間隙,不為null時(shí)具有強(qiáng)制指定的高度。
同樣我們還要考慮方向:layoutManager為橫向和豎向的情況,無它,只是畫的位置不同而已。

話不多說了,上代碼:

import android.graphics.drawable.Drawable;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;

public class ViewTypeDivider extends ItemHolderDivider {

  @Override
  protected int keyFrom(RecyclerView.ViewHolder holder) {
    return holder.getItemViewType();
  }

  public ViewTypeDivider put(int viewType, Drawable drawable) {
    putDrawable(viewType, drawable);
    return this;
  }

  public ViewTypeDivider put(int viewType, @Nullable Drawable drawable, int height) {
    putHeight(viewType, drawable, height);
    return this;
  }
}
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.annotation.Nullable;
import android.support.v4.util.SparseArrayCompat;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;

abstract class ItemHolderDivider extends RecyclerView.ItemDecoration {
  private final SparseArrayCompat<Drawable> mDividers = new SparseArrayCompat<>(2);
  private final SparseArrayCompat<Integer> mHeights = new SparseArrayCompat<>(2);

  protected abstract int keyFrom(RecyclerView.ViewHolder holder);

  @Override
  public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
    final int childCount = parent.getChildCount();
    final int width = parent.getWidth();
    final int height = parent.getHeight();
    for (int childViewIndex = 0; childViewIndex < childCount; childViewIndex++) {
      final View view = parent.getChildAt(childViewIndex);
      RecyclerView.ViewHolder holder = parent.getChildViewHolder(view);
      int key = keyFrom(holder);
      if (isVertical(parent)) {
        drawBottom(c, key, (int) view.getY() + view.getHeight(), width);
        drawTop(c, -key, (int) view.getY(), width);
      } else {
        drawRight(c, key, (int) view.getX() + view.getWidth(), height);
        drawLeft(c, -key, (int) view.getX(), height);
      }
    }
  }

  @Override
  public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
                RecyclerView.State state) {
    RecyclerView.ViewHolder holder = parent.getChildViewHolder(view);
    int key = keyFrom(holder);
    if (isVertical(parent)) {
      outRect.bottom = getHeight(key);
      outRect.top = getHeight(-key);
    } else {
      outRect.right = getHeight(key);
      outRect.left = getHeight(-key);
    }
  }

  private void drawBottom(Canvas c, int key, int y, int width) {
    Drawable d = mDividers.get(key);
    if (d != null) {
      d.setBounds(0, y, width, y + getHeight(key, d));
      d.draw(c);
    }
  }

  private void drawTop(Canvas c, int key, int y, int width) {
    Drawable d = mDividers.get(key);
    if (d != null) {
      d.setBounds(0, y - getHeight(key, d), width, y);
      d.draw(c);
    }
  }

  private void drawRight(Canvas c, int key, int x, int height) {
    Drawable d = mDividers.get(key);
    if (d != null) {
      d.setBounds(x, 0, x + getHeight(key, d), height);
      d.draw(c);
    }
  }

  private void drawLeft(Canvas c, int key, int x, int height) {
    Drawable d = mDividers.get(key);
    if (d != null) {
      d.setBounds(x - getHeight(key, d), 0, x, height);
      d.draw(c);
    }
  }

  final void putDrawable(int key, Drawable drawable) {
    mDividers.put(key, drawable);
  }

  final void putHeight(int key, @Nullable Drawable drawable, int height) {
    if (drawable != null) {
      mDividers.put(key, drawable);
    }
    mHeights.put(key, height);
  }

  private int getHeight(int key) {
    Drawable d = mDividers.get(key);
    return getHeight(key, d);
  }

  private int getHeight(int key, @Nullable Drawable d) {
    int index = mHeights.indexOfKey(key);
    return index < 0 ? d == null ? 0 : d.getIntrinsicHeight() : mHeights.valueAt(index);
  }

  private boolean isVertical(RecyclerView parent) {
    RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
    return !(layoutManager instanceof LinearLayoutManager) ||
        ((LinearLayoutManager) layoutManager).getOrientation() == LinearLayoutManager.VERTICAL;
  }
}

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持億速云。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI