@Override public void getItemOffsets( Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { super.getItemOffsets(outRect, view, parent, state); if (mDivider == null) { return; } int position = parent.getChildAdapterPosition(view); if (position == RecyclerView.NO_POSITION || (position == 0 && !mShowFirstDivider)) { return; } if (mOrientation == -1) getOrientation(parent); if (mOrientation == LinearLayoutManager.VERTICAL) { outRect.top = mDivider.getIntrinsicHeight(); if (mShowLastDivider && position == (state.getItemCount() - 1)) { outRect.bottom = outRect.top; } } else { outRect.left = mDivider.getIntrinsicWidth(); if (mShowLastDivider && position == (state.getItemCount() - 1)) { outRect.right = outRect.left; } } }
@Override public void onMeasure( RecyclerView.Recycler recycler, RecyclerView.State state, int widthSpec, int heightSpec) { View view = null; if (state.getItemCount() > 0) { view = recycler.getViewForPosition(0); } int height = 0; int width = 0; if (view != null) { RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) view.getLayoutParams(); int childWidthSpec = ViewGroup.getChildMeasureSpec( widthSpec, getPaddingLeft() + getPaddingRight(), params.width); int childHeightSpec = ViewGroup.getChildMeasureSpec( heightSpec, getPaddingTop() + getPaddingBottom(), params.height); view.measure(childWidthSpec, childHeightSpec); width = view.getMeasuredWidth() + params.leftMargin + params.rightMargin; height = view.getMeasuredHeight() + params.bottomMargin + params.topMargin; recycler.recycleView(view); } setMeasuredDimension(width, height); }
@Override public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) { if (mDivider == null) { super.onDrawOver(c, parent, state); return; } // Initialization needed to avoid compiler warning int left = 0, right = 0, top = 0, bottom = 0, size; int orientation = mOrientation != -1 ? mOrientation : getOrientation(parent); int childCount = parent.getChildCount(); if (orientation == LinearLayoutManager.VERTICAL) { size = mDivider.getIntrinsicHeight(); left = parent.getPaddingLeft(); right = parent.getWidth() - parent.getPaddingRight(); } else { // horizontal size = mDivider.getIntrinsicWidth(); top = parent.getPaddingTop(); bottom = parent.getHeight() - parent.getPaddingBottom(); } for (int i = mShowFirstDivider ? 0 : 1; i < childCount; i++) { View child = parent.getChildAt(i); RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams(); if (orientation == LinearLayoutManager.VERTICAL) { top = child.getTop() - params.topMargin - size; bottom = top + size; } else { // horizontal left = child.getLeft() - params.leftMargin; right = left + size; } mDivider.setBounds(left, top, right, bottom); mDivider.draw(c); } // show last divider if (mShowLastDivider && childCount > 0) { View child = parent.getChildAt(childCount - 1); if (parent.getChildAdapterPosition(child) == (state.getItemCount() - 1)) { RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams(); if (orientation == LinearLayoutManager.VERTICAL) { top = child.getBottom() + params.bottomMargin; bottom = top + size; } else { // horizontal left = child.getRight() + params.rightMargin; right = left + size; } mDivider.setBounds(left, top, right, bottom); mDivider.draw(c); } } }
@Override public void onMeasure( RecyclerView.Recycler recycler, RecyclerView.State state, int widthSpec, int heightSpec) { int[] mMeasuredDimension = new int[2]; final int widthMode = View.MeasureSpec.getMode(widthSpec); final int heightMode = View.MeasureSpec.getMode(heightSpec); final int heightSize = View.MeasureSpec.getSize(heightSpec); int width = 0; int height = 0; LogUtils.d("state:" + state.toString()); for (int i = 0; i < getItemCount(); i++) { try { measureScrapChild( recycler, i, widthSpec, View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED), mMeasuredDimension); } catch (IndexOutOfBoundsException e) { e.printStackTrace(); } if (getOrientation() == HORIZONTAL) { width = width + mMeasuredDimension[0]; if (i == 0) { height = mMeasuredDimension[1]; } } else { height = height + mMeasuredDimension[1]; if (i == 0) { width = mMeasuredDimension[0]; } } } switch (widthMode) { case View.MeasureSpec.EXACTLY: case View.MeasureSpec.AT_MOST: case View.MeasureSpec.UNSPECIFIED: } switch (heightMode) { case View.MeasureSpec.EXACTLY: height = heightSize; case View.MeasureSpec.AT_MOST: case View.MeasureSpec.UNSPECIFIED: } setMeasuredDimension(widthSpec, height); }
@Override public void onMeasure( RecyclerView.Recycler recycler, RecyclerView.State state, int widthSpec, int heightSpec) { final int widthMode = View.MeasureSpec.getMode(widthSpec); final int heightMode = View.MeasureSpec.getMode(heightSpec); final int widthSize = View.MeasureSpec.getSize(widthSpec); final int heightSize = View.MeasureSpec.getSize(heightSpec); final boolean hasWidthSize = widthMode != View.MeasureSpec.UNSPECIFIED; final boolean hasHeightSize = heightMode != View.MeasureSpec.UNSPECIFIED; final boolean exactWidth = widthMode == View.MeasureSpec.EXACTLY; final boolean exactHeight = heightMode == View.MeasureSpec.EXACTLY; final int unspecified = makeUnspecifiedSpec(); if (exactWidth && exactHeight) { // in case of exact calculations for both dimensions let's use default "onMeasure" // implementation super.onMeasure(recycler, state, widthSpec, heightSpec); return; } final boolean vertical = getOrientation() == VERTICAL; initChildDimensions(widthSize, heightSize, vertical); int width = 0; int height = 0; // it's possible to get scrap views in recycler which are bound to old (invalid) adapter // entities. This // happens because their invalidation happens after "onMeasure" method. As a workaround let's // clear the // recycler now (it should not cause any performance issues while scrolling as "onMeasure" is // never // called whiles scrolling) recycler.clear(); final int stateItemCount = state.getItemCount(); final int adapterItemCount = getItemCount(); // adapter always contains actual data while state might contain old data (f.e. data before the // animation is // done). As we want to measure the view with actual data we must use data from the adapter and // not from the // state for (int i = 0; i < adapterItemCount; i++) { if (vertical) { if (!hasChildSize) { if (i < stateItemCount) { // we should not exceed state count, otherwise we'll get IndexOutOfBoundsException. For // such items // we will use previously calculated dimensions measureChild(recycler, i, widthSize, unspecified, childDimensions); } else { logMeasureWarning(i); } } height += childDimensions[CHILD_HEIGHT]; if (i == 0) { width = childDimensions[CHILD_WIDTH]; } if (hasHeightSize && height >= heightSize) { break; } } else { if (!hasChildSize) { if (i < stateItemCount) { // we should not exceed state count, otherwise we'll get IndexOutOfBoundsException. For // such items // we will use previously calculated dimensions measureChild(recycler, i, unspecified, heightSize, childDimensions); } else { logMeasureWarning(i); } } width += childDimensions[CHILD_WIDTH]; if (i == 0) { height = childDimensions[CHILD_HEIGHT]; } if (hasWidthSize && width >= widthSize) { break; } } } if (exactWidth) { width = widthSize; } else { width += getPaddingLeft() + getPaddingRight(); if (hasWidthSize) { width = Math.min(width, widthSize); } } if (exactHeight) { height = heightSize; } else { height += getPaddingTop() + getPaddingBottom(); if (hasHeightSize) { height = Math.min(height, heightSize); } } setMeasuredDimension(width, height); if (view != null && overScrollMode == ViewCompat.OVER_SCROLL_IF_CONTENT_SCROLLS) { final boolean fit = (vertical && (!hasHeightSize || height < heightSize)) || (!vertical && (!hasWidthSize || width < widthSize)); ViewCompat.setOverScrollMode( view, fit ? ViewCompat.OVER_SCROLL_NEVER : ViewCompat.OVER_SCROLL_ALWAYS); } }