yqritc/RecyclerView-FlexibleDivider

This library is not good for GridLayoutManager. Some Suggesttion.

liaolintao opened this issue · 0 comments

Problem

Method(com.yqritc.recyclerviewflexibledivider.FlexibleDividerDecoration#getGroupIndex )
calls frequently, and that method consume too much time, ui thread do too much.

google source code :

GridLayoutManager.SpanSizeLookup#getSpanGroupIndex(int, int) .
https://developer.android.com/reference/android/support/v7/widget/GridLayoutManager.SpanSizeLookup.html?hl=ja#getSpanGroupIndex(int;

        public int getSpanGroupIndex(int adapterPosition, int spanCount) {
            int span = 0;
            int group = 0;
            int positionSpanSize = getSpanSize(adapterPosition);
            for (int i = 0; i < adapterPosition; i++) {
                int size = getSpanSize(i);
                span += size;
                if (span == spanCount) {
                    span = 0;
                    group++;
                } else if (span > spanCount) {
                    // did not fit, moving to next row / column
                    span = size;
                    group++;
                }
            }
            if (span + positionSpanSize > spanCount) {
                group++;
            }
            return group;
        }

My Suggesttion

Please dont't frequently use method GridLayoutManager.SpanSizeLookup#getSpanGroupIndex(int, int) .
I do it ,and ui thread is good for show.

My Simple Code for GridLayoutManager

import android.graphics.Canvas;
import android.graphics.Rect;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.OrientationHelper;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.ItemDecoration;
import android.support.v7.widget.RecyclerView.State;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.view.View;

public class ListSpacingDecoration extends ItemDecoration {

  private static final String TAG = ListSpacingDecoration.class.getSimpleName();

  private static final int VERTICAL = OrientationHelper.VERTICAL;

  private int orientation = -1;
  private int spanCount = -1;
  private int spacing;
  private int halfSpacing;

  public ListSpacingDecoration(int spacing) {
    super();
    this.spacing = spacing;
    this.halfSpacing = spacing / 2;
  }

  /**
   * 可以通过outRect.set()为每个Item设置一定的偏移量,主要用于绘制Decorator
   */
  @Override
  public void getItemOffsets(Rect outRect, final View view, RecyclerView parent, State state) {

    // super.getItemOffsets(outRect, view, parent, state);
    if (orientation == -1) {
      orientation = getOrientation(parent);
    }

    if (spanCount == -1) {
      spanCount = getTotalSpan(parent);
    }

    int childCount = parent.getLayoutManager().getItemCount();
    int childIndex = parent.getChildAdapterPosition(view);

    int itemSpanSize = getItemSpanSize(parent, childIndex);
    int spanIndex = getItemSpanIndex(parent, childIndex);

//    LogUtils.d(TAG, "getItemOffsets childCount = " + childCount + " - childIndex = " + childIndex + " : itemSpanSize = "
//        + itemSpanSize + " : spanIndex = " + spanIndex);
    /* INVALID SPAN */
    if (spanCount < 1)
      return;

    setSpacings(outRect, parent, childCount, childIndex, itemSpanSize, spanIndex);
  }

  /**
   * onDraw方法先于drawChildren
   */
  @Override
  public void onDraw(Canvas c, RecyclerView parent, State state) {
    // TODO
    super.onDraw(c, parent, state);
  }

  /**
   * onDrawOver在drawChildren之后,一般我们选择复写其中一个即可
   */
  @Override
  public void onDrawOver(Canvas c, RecyclerView parent, State state) {
    // TODO
    super.onDrawOver(c, parent, state);
  }

  protected void setSpacings(Rect outRect, RecyclerView parent, int childCount, int childIndex, int itemSpanSize,
      int spanIndex) {

    outRect.top = halfSpacing;
    outRect.bottom = halfSpacing;
    outRect.left = halfSpacing;
    outRect.right = halfSpacing;

    if (isTopEdge(parent, childCount, childIndex, itemSpanSize, spanIndex)) {
      outRect.top = spacing;
    }

    if (isLeftEdge(parent, childCount, childIndex, itemSpanSize, spanIndex)) {
      // outRect.left = spacing;
      outRect.left = 0;
    }

    if (isRightEdge(parent, childCount, childIndex, itemSpanSize, spanIndex)) {
      // outRect.right = spacing;
      outRect.right = 0;
    }

    if (isBottomEdge(parent, childCount, childIndex, itemSpanSize, spanIndex)) {
      outRect.bottom = spacing;
    }
  }

  @SuppressWarnings("all")
  protected int getTotalSpan(RecyclerView parent) {

    RecyclerView.LayoutManager mgr = parent.getLayoutManager();
    if (mgr instanceof GridLayoutManager) {
      return ((GridLayoutManager) mgr).getSpanCount();
    } else if (mgr instanceof StaggeredGridLayoutManager) {
      return ((StaggeredGridLayoutManager) mgr).getSpanCount();
    } else if (mgr instanceof LinearLayoutManager) {
      return 1;
    }

    return -1;
  }

  @SuppressWarnings("all")
  protected int getItemSpanSize(RecyclerView parent, int childIndex) {

    RecyclerView.LayoutManager mgr = parent.getLayoutManager();
    if (mgr instanceof GridLayoutManager) {
      return ((GridLayoutManager) mgr).getSpanSizeLookup().getSpanSize(childIndex);
    } else if (mgr instanceof StaggeredGridLayoutManager) {
      return 1;
    } else if (mgr instanceof LinearLayoutManager) {
      return 1;
    }

    return -1;
  }

  @SuppressWarnings("all")
  protected int getItemSpanIndex(RecyclerView parent, int childIndex) {

    RecyclerView.LayoutManager mgr = parent.getLayoutManager();
    if (mgr instanceof GridLayoutManager) {
      return ((GridLayoutManager) mgr).getSpanSizeLookup().getSpanIndex(childIndex, spanCount);
    } else if (mgr instanceof StaggeredGridLayoutManager) {
      return childIndex % spanCount;
    } else if (mgr instanceof LinearLayoutManager) {
      return 0;
    }

    return -1;
  }

  @SuppressWarnings("all")
  protected int getOrientation(RecyclerView parent) {

    RecyclerView.LayoutManager mgr = parent.getLayoutManager();
    if (mgr instanceof LinearLayoutManager) {
      return ((LinearLayoutManager) mgr).getOrientation();
    } else if (mgr instanceof GridLayoutManager) {
      return ((GridLayoutManager) mgr).getOrientation();
    } else if (mgr instanceof StaggeredGridLayoutManager) {
      return ((StaggeredGridLayoutManager) mgr).getOrientation();
    }

    return VERTICAL;
  }

  protected boolean isLeftEdge(RecyclerView parent, int childCount, int childIndex, int itemSpanSize, int spanIndex) {

    if (orientation == VERTICAL) {

      return spanIndex == 0;

    } else {

      return (childIndex == 0) || isFirstItemEdgeValid((childIndex < spanCount), parent, childIndex);
    }
  }

  protected boolean isRightEdge(RecyclerView parent, int childCount, int childIndex, int itemSpanSize, int spanIndex) {

    if (orientation == VERTICAL) {

      return (spanIndex + itemSpanSize) == spanCount;

    } else {

      return isLastItemEdgeValid((childIndex >= childCount - spanCount), parent, childCount, childIndex, spanIndex);
    }
  }

  protected boolean isTopEdge(RecyclerView parent, int childCount, int childIndex, int itemSpanSize, int spanIndex) {

    if (orientation == VERTICAL) {

      return (childIndex == 0) || isFirstItemEdgeValid((childIndex < spanCount), parent, childIndex);

    } else {

      return spanIndex == 0;
    }
  }

  protected boolean isBottomEdge(RecyclerView parent, int childCount, int childIndex, int itemSpanSize, int spanIndex) {

    if (orientation == VERTICAL) {

      return isLastItemEdgeValid((childIndex >= childCount - spanCount), parent, childCount, childIndex, spanIndex);

    } else {

      return (spanIndex + itemSpanSize) == spanCount;
    }
  }

  protected boolean isFirstItemEdgeValid(boolean isOneOfFirstItems, RecyclerView parent, int childIndex) {

    int totalSpanArea = 0;
    if (isOneOfFirstItems) {
      for (int i = childIndex; i >= 0; i--) {
        totalSpanArea = totalSpanArea + getItemSpanSize(parent, i);
      }
    }

    return isOneOfFirstItems && totalSpanArea <= spanCount;
  }

  protected boolean isLastItemEdgeValid(boolean isOneOfLastItems, RecyclerView parent, int childCount, int childIndex,
      int spanIndex) {

    int totalSpanRemaining = 0;
    if (isOneOfLastItems) {
      for (int i = childIndex; i < childCount; i++) {
        totalSpanRemaining = totalSpanRemaining + getItemSpanSize(parent, i);
      }
    }

    return isOneOfLastItems && (totalSpanRemaining <= spanCount - spanIndex);
  }
}