Java tutorial
/** * Copyright 2016 bingoogolapple * <p/> * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * <p/> * http://www.apache.org/licenses/LICENSE-2.0 * <p/> * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package cn.bingoogolapple.androidcommon.adapter; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.support.annotation.ColorInt; import android.support.annotation.ColorRes; import android.support.annotation.DimenRes; import android.support.annotation.DrawableRes; import android.support.annotation.IntRange; import android.support.v4.content.ContextCompat; import android.support.v7.widget.RecyclerView; import android.view.View; import android.widget.LinearLayout; /** * : :bingoogolapple@gmail.com * :17/1/6 ?4:04 * ??:RecyclerView */ public class BGADivider extends RecyclerView.ItemDecoration { private Drawable mDividerDrawable; private int mMarginLeft; private int mMarginRight; private int mOrientation = LinearLayout.VERTICAL; private int mStartSkipCount = 1; private int mEndSkipCount = 0; private int mSize = 1; private Delegate mDelegate; private BGADivider(@DrawableRes int drawableResId) { mDividerDrawable = ContextCompat.getDrawable(BGAAdapterUtil.getApp(), drawableResId); mSize = Math.min(mDividerDrawable.getIntrinsicHeight(), mDividerDrawable.getIntrinsicWidth()); } /** * drawable ? * * @param drawableResId * @return */ public static BGADivider newDrawableDivider(@DrawableRes int drawableResId) { return new BGADivider(drawableResId); } /** * shape ? * * @return */ public static BGADivider newShapeDivider() { return new BGADivider(R.drawable.bga_adapter_divider_shape); } /** * * * @return */ public static BGADivider newBitmapDivider() { return new BGADivider(R.mipmap.bga_adapter_divider_bitmap); } /** * ? * * @param delegate * @return */ public BGADivider setDelegate(Delegate delegate) { mDelegate = delegate; return this; } /** * ???? id * * @param resId * @return */ public BGADivider setBothMarginResource(@DimenRes int resId) { mMarginLeft = BGAAdapterUtil.getDimensionPixelOffset(resId); mMarginRight = mMarginLeft; return this; } /** * ??? * * @param bothMarginDp ?? dp * @return */ public BGADivider setBothMarginDp(int bothMarginDp) { mMarginLeft = BGAAdapterUtil.dp2px(bothMarginDp); mMarginRight = mMarginLeft; return this; } /** * ?? id * * @param resId * @return */ public BGADivider setMarginLeftResource(@DimenRes int resId) { mMarginLeft = BGAAdapterUtil.getDimensionPixelOffset(resId); return this; } /** * ? * * @param marginLeftDp ?? dp * @return */ public BGADivider setMarginLeftDp(int marginLeftDp) { mMarginLeft = BGAAdapterUtil.dp2px(marginLeftDp); return this; } /** * ??? id * * @param resId * @return */ public BGADivider setMarginRightResource(@DimenRes int resId) { mMarginRight = BGAAdapterUtil.getDimensionPixelOffset(resId); return this; } /** * ?? * * @param marginRightDp ?? dp * @return */ public BGADivider setMarginRightDp(int marginRightDp) { mMarginRight = BGAAdapterUtil.dp2px(marginRightDp); return this; } /** * ? id * * @param resId * @param isSrcTop * @return */ public BGADivider setColorResource(@ColorRes int resId, boolean isSrcTop) { return setColor(BGAAdapterUtil.getColor(resId), isSrcTop); } /** * * * @param color * @param isSrcTop * @return */ public BGADivider setColor(@ColorInt int color, boolean isSrcTop) { mDividerDrawable.setColorFilter(color, isSrcTop ? PorterDuff.Mode.SRC_ATOP : PorterDuff.Mode.SRC); return this; } /** * ? * * @return */ public BGADivider setHorizontal() { mOrientation = LinearLayout.HORIZONTAL; return this; } /** * Bitmap UI ??? * * @return */ public BGADivider rotateDivider() { if (mDividerDrawable != null && mDividerDrawable instanceof BitmapDrawable) { mDividerDrawable = BGAAdapterUtil.rotateBitmap(((BitmapDrawable) mDividerDrawable).getBitmap()); } return this; } /** * ? 1? item * * @param startSkipCount * @return */ public BGADivider setStartSkipCount(@IntRange(from = 0) int startSkipCount) { mStartSkipCount = startSkipCount; if (mStartSkipCount < 0) { mStartSkipCount = 0; } return this; } /** * ? * * @param endSkipCount * @return */ public BGADivider setEndSkipCount(@IntRange(from = 0) int endSkipCount) { mEndSkipCount = endSkipCount; if (mEndSkipCount < 0) { mEndSkipCount = 0; } return this; } /** * ? id * * @param resId * @return */ public BGADivider setSizeResource(@DimenRes int resId) { mSize = BGAAdapterUtil.getDimensionPixelOffset(resId); return this; } /** * * * @param sizeDp ?? dp * @return */ public BGADivider setSizeDp(int sizeDp) { mSize = BGAAdapterUtil.dp2px(sizeDp); return this; } /** * ?? * * @return */ public int getMarginLeft() { return mMarginLeft; } /** * ??? * * @return */ public int getMarginRight() { return mMarginRight; } private BGAHeaderAndFooterAdapter getHeaderAndFooterAdapter(RecyclerView parent) { RecyclerView.Adapter adapter = parent.getAdapter(); if (adapter instanceof BGAHeaderAndFooterAdapter) { return (BGAHeaderAndFooterAdapter) adapter; } else { return null; } } private boolean isNeedSkip(int childAdapterPosition, BGAHeaderAndFooterAdapter headerAndFooterAdapter, int realChildAdapterPosition, int realItemCount) { if (headerAndFooterAdapter != null && headerAndFooterAdapter.isHeaderViewOrFooterView(childAdapterPosition)) { // header footer return true; } int lastPosition = realItemCount - 1; // ? mEndSkipCount if (realChildAdapterPosition > lastPosition - mEndSkipCount) { return true; } // ? mStartSkipCount // 1 if (realChildAdapterPosition < mStartSkipCount) { return true; } if (mDelegate != null) { return mDelegate.isNeedSkip(realChildAdapterPosition, realItemCount); } // ? return false; } @Override public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { if (parent.getLayoutManager() == null || parent.getAdapter() == null) { return; } int childAdapterPosition = parent.getChildAdapterPosition(view); int itemCount = parent.getAdapter().getItemCount(); int realChildAdapterPosition = childAdapterPosition; int realItemCount = itemCount; BGAHeaderAndFooterAdapter headerAndFooterAdapter = getHeaderAndFooterAdapter(parent); if (headerAndFooterAdapter != null) { // ?? item realChildAdapterPosition = headerAndFooterAdapter.getRealItemPosition(childAdapterPosition); // ?? item realItemCount = headerAndFooterAdapter.getRealItemCount(); } if (isNeedSkip(childAdapterPosition, headerAndFooterAdapter, realChildAdapterPosition, realItemCount)) { outRect.set(0, 0, 0, 0); } else { if (mDelegate != null && mDelegate.isNeedCustom(realChildAdapterPosition, realItemCount)) { mDelegate.getItemOffsets(this, realChildAdapterPosition, realItemCount, outRect); } else { if (mOrientation == LinearLayout.VERTICAL) { getVerticalItemOffsets(outRect); } else { outRect.set(mSize, 0, 0, 0); } } } } public void getVerticalItemOffsets(Rect outRect) { outRect.set(0, mSize, 0, 0); } @Override public void onDrawOver(Canvas canvas, RecyclerView parent, RecyclerView.State state) { if (parent.getLayoutManager() == null || parent.getAdapter() == null) { return; } int itemCount = parent.getAdapter().getItemCount(); BGAHeaderAndFooterAdapter headerAndFooterAdapter = getHeaderAndFooterAdapter(parent); // header footer ? item int realItemCount = itemCount; if (headerAndFooterAdapter != null) { // ?? item realItemCount = headerAndFooterAdapter.getRealItemCount(); } if (mOrientation == LinearLayout.VERTICAL) { drawVertical(canvas, parent, headerAndFooterAdapter, itemCount, realItemCount); } else { drawHorizontal(canvas, parent); } } private void drawVertical(Canvas canvas, RecyclerView parent, BGAHeaderAndFooterAdapter headerAndFooterAdapter, int itemCount, int realItemCount) { int dividerLeft = parent.getPaddingLeft() + mMarginLeft; int dividerRight = parent.getWidth() - parent.getPaddingRight() - mMarginRight; View itemView; RecyclerView.LayoutParams itemLayoutParams; int realChildAdapterPosition; for (int childPosition = 0; childPosition < itemCount; childPosition++) { itemView = parent.getChildAt(childPosition); if (itemView == null || itemView.getLayoutParams() == null) { continue; } int childAdapterPosition = parent.getChildAdapterPosition(itemView); realChildAdapterPosition = getRealChildAdapterPosition(childAdapterPosition, headerAndFooterAdapter); if (isNeedSkip(childAdapterPosition, headerAndFooterAdapter, realChildAdapterPosition, realItemCount)) { continue; } itemLayoutParams = (RecyclerView.LayoutParams) itemView.getLayoutParams(); int dividerBottom = itemView.getTop() - itemLayoutParams.topMargin; if (mDelegate != null && mDelegate.isNeedCustom(realChildAdapterPosition, realItemCount)) { mDelegate.drawVertical(this, canvas, dividerLeft, dividerRight, dividerBottom, realChildAdapterPosition, realItemCount); } else { drawVertical(canvas, dividerLeft, dividerRight, dividerBottom); } } } public void drawVertical(Canvas canvas, int dividerLeft, int dividerRight, int itemTop) { int dividerBottom = itemTop; int dividerTop = dividerBottom - mSize; mDividerDrawable.setBounds(dividerLeft, dividerTop, dividerRight, dividerBottom); mDividerDrawable.draw(canvas); } private int getRealChildAdapterPosition(int childAdapterPosition, BGAHeaderAndFooterAdapter headerAndFooterAdapter) { if (headerAndFooterAdapter != null) { // ?? item return headerAndFooterAdapter.getRealItemPosition(childAdapterPosition); } return childAdapterPosition; } private void drawHorizontal(Canvas canvas, RecyclerView parent) { } public interface Delegate { boolean isNeedSkip(int position, int itemCount); boolean isNeedCustom(int position, int itemCount); void getItemOffsets(BGADivider divider, int position, int itemCount, Rect outRect); void drawVertical(BGADivider divider, Canvas canvas, int dividerLeft, int dividerRight, int dividerBottom, int position, int itemCount); } public static class SimpleDelegate implements Delegate { protected Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); public SimpleDelegate() { mPaint.setDither(true); mPaint.setAntiAlias(true); initAttr(); } protected void initAttr() { } @Override public boolean isNeedSkip(int position, int itemCount) { return false; } @Override public boolean isNeedCustom(int position, int itemCount) { return false; } @Override public void getItemOffsets(BGADivider divider, int position, int itemCount, Rect outRect) { } @Override public void drawVertical(BGADivider divider, Canvas canvas, int dividerLeft, int dividerRight, int dividerBottom, int position, int itemCount) { } } /** * ? */ public static abstract class SuspensionCategoryDelegate extends SimpleDelegate { protected int mCategoryBackgroundColor; protected int mCategoryTextColor; protected int mCategoryPaddingLeft; protected int mCategoryTextSize; protected int mCategoryHeight; protected float mCategoryTextOffset; @Override protected void initAttr() { mCategoryBackgroundColor = Color.parseColor("#F2F2F2"); mCategoryTextColor = Color.parseColor("#848484"); mCategoryPaddingLeft = BGAAdapterUtil.dp2px(16); mCategoryTextSize = BGAAdapterUtil.sp2px(14); mCategoryHeight = BGAAdapterUtil.dp2px(32); initCategoryAttr(); mPaint.setStyle(Paint.Style.FILL); calculateCategoryTextOffset(); } /** * ??? */ public void calculateCategoryTextOffset() { mPaint.setTextSize(mCategoryTextSize); Rect rect = new Rect(); mPaint.getTextBounds("", 0, 2, rect); int textHeight = rect.height(); mCategoryTextOffset = (mCategoryHeight - textHeight) / 2.0f; } /** * ?? */ protected void initCategoryAttr() { } @Override public boolean isNeedCustom(int position, int itemCount) { // ? return true; } @Override public void getItemOffsets(BGADivider divider, int position, int itemCount, Rect outRect) { if (isCategory(position)) { // outRect.set(0, mCategoryHeight, 0, 0); } else { // ? BGADivider getVerticalItemOffsets ? item divider.getVerticalItemOffsets(outRect); } } @Override public void drawVertical(BGADivider divider, Canvas canvas, int dividerLeft, int dividerRight, int dividerBottom, int position, int itemCount) { if (isCategory(position)) { drawCategory(divider, canvas, dividerLeft, dividerRight, dividerBottom, getCategoryName(position)); } else { divider.drawVertical(canvas, dividerLeft, dividerRight, dividerBottom); } // ??mCategoryHeight dividerBottom?? drawCategory(divider, canvas, dividerLeft, dividerRight, mCategoryHeight, getCategoryName(getFirstVisibleItemPosition())); } /** * ?? * * @param position * @return */ protected abstract boolean isCategory(int position); /** * ???? * * @param position * @return */ protected abstract String getCategoryName(int position); /** * ????? * * @return */ protected abstract int getFirstVisibleItemPosition(); protected void drawCategory(BGADivider divider, Canvas canvas, int dividerLeft, int dividerRight, int dividerBottom, String category) { // mPaint.setColor(mCategoryBackgroundColor); canvas.drawRect(dividerLeft - divider.getMarginLeft(), dividerBottom - mCategoryHeight, dividerRight + divider.getMarginRight(), dividerBottom, mPaint); // mPaint.setColor(mCategoryTextColor); canvas.drawText(category, 0, category.length(), mCategoryPaddingLeft, dividerBottom - mCategoryTextOffset, mPaint); } } }