前言
一個實現快速索引的側邊欄,已經封裝完整,可以直接使用
使用它的一些注意點
我是用RecyclerView來配合使用它的,可以使用了2個方法來滾動到指定位置,二選其一,一個是快速滾動,一個是平滑滾動。但是滾動的itemPosition需要你自己提前計算好位置,不能在適配器里的onBindViewHolder方法來獲取指定位置,因為這個方法如果列表沒有滾動到指定位置是不會執行的。這里我是用了一個Map集合來提前計算並且保存所有首字母code的位置,然后在根據SideBarView的回調在從Map里取需要滾動的itemPosition位置。
mRecyclerView.scrollToPosition(itemPosition);
mRecyclerView.smoothScrollToPosition(itemPosition);
效果圖
代碼
import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Point; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import androidx.annotation.ColorInt; import androidx.annotation.Nullable; import java.util.ArrayList; import java.util.List; /** * content: 自定義的字母定位側邊欄 * time: 2020-4-24 * * @author: guanxinjin */ public class SideBarView extends View { private List<String> mContentDataList = new ArrayList<>(); private int mBackgroundColor = Color.TRANSPARENT; private int mPaddingTop = 0; private int mPaddingBottom = 0; private int mPaddingLeft = 0; private int mPaddingRight = 0; private float mTextSize = 15; private int mTextColor = Color.BLACK; private int mItemSpace = 15; //自定義的item間隔 private boolean mIsEqualItemSpace = true; //是否按View的高度均分item的高度間隔 private Paint mPaint; private int mWidth = 0; private int mHeight = 0; private Point mOneItemPoint = new Point(); //第一個item的坐標值 private int mItemHeightSize = 0; //單個Item的高度尺寸 private OnClickListener mListener; public SideBarView(Context context) { super(context); initPaint(); } public SideBarView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); initPaint(); } public SideBarView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initPaint(); } public SideBarView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); initPaint(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); mWidth = MeasureSpec.getSize(widthMeasureSpec); mHeight = MeasureSpec.getSize(heightMeasureSpec); if (mIsEqualItemSpace) {//均分Item間距模式 mItemHeightSize = (mHeight - (mPaddingTop + mPaddingBottom)) / mContentDataList.size();//高度 - 上下邊距 / Item的數量 = 一個Item的高度 } else { //自定義Item間距模式 mItemHeightSize = ((mHeight - (mPaddingTop + mPaddingBottom)) / mContentDataList.size()) + mItemSpace; } mOneItemPoint.x = (mWidth - (mPaddingLeft + mPaddingRight)) / 2; //寬度 - 左右邊距 / 2 = 第一個Item的X坐標值 mOneItemPoint.y = mPaddingTop + mItemHeightSize; //上邊距 + Item高度 = 第一個Item的Y坐標值 setMeasuredDimension(mWidth, mHeight); } @Override public boolean onTouchEvent(MotionEvent event) { int action = event.getAction(); int itemAllHeight = mHeight - (mPaddingTop + mPaddingBottom); switch (action) { case MotionEvent.ACTION_DOWN: //根據當前點擊的位置與整體item的全部高度除比,在將除得后的數字四舍五入獲得對應集合中的位置。 int downPosition = Math.round(mContentDataList.size() / (itemAllHeight / event.getY())); downPosition = Math.max(downPosition, 1); //不允許有小於1的值 downPosition = Math.min(downPosition, mContentDataList.size());//不允許有大於集合長度的值 downPosition = downPosition - 1; if (mListener != null) { mListener.onItemDown(downPosition, mContentDataList.get(downPosition)); } return true; case MotionEvent.ACTION_MOVE: int movePosition = Math.round(mContentDataList.size() / (itemAllHeight / event.getY())); movePosition = Math.max(movePosition, 1); movePosition = Math.min(movePosition, mContentDataList.size()); movePosition = movePosition - 1; if (mListener != null) { mListener.onItemMove(movePosition, mContentDataList.get(movePosition)); } return true; case MotionEvent.ACTION_UP: int upPosition = Math.round(mContentDataList.size() / (itemAllHeight / event.getY())); upPosition = Math.max(upPosition, 1); upPosition = Math.min(upPosition, mContentDataList.size()); upPosition = upPosition - 1; if (mListener != null) { mListener.onItemUp(upPosition, mContentDataList.get(upPosition)); } return true; } return super.onTouchEvent(event); } private void initPaint() { mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setColor(mTextColor); mPaint.setTextSize(mTextSize); mPaint.setTextAlign(Paint.Align.CENTER); } public void setContentDataList(List<String> list) { mContentDataList.clear(); mContentDataList.addAll(list); postInvalidate(); } /** * 設置文字大小 * * @param spValue 單位sp */ public void setTextSize(float spValue) { mTextSize = sp2px(spValue); mPaint.setTextSize(mTextSize); postInvalidate(); } public void setTextColor(@ColorInt int color) { mTextColor = color; mPaint.setColor(mTextColor); postInvalidate(); } public void setBackgroundColor(@ColorInt int color) { mBackgroundColor = color; postInvalidate(); } /** * 設置是否根據View的高度均分item的間距 * * @param isEqualItemSpace true=使用均分 false=不使用均分 */ public void setEqualItemSpace(boolean isEqualItemSpace) { mIsEqualItemSpace = isEqualItemSpace; postInvalidate(); } /** * item的間距 * * @param itemSpace 單位dp */ public void itemSpace(int itemSpace) { mItemSpace = dip2px(itemSpace); mIsEqualItemSpace = false; postInvalidate(); } /** * 設置內邊距 * * @param top 上邊距,單位dp * @param bottom 下邊距,單位dp * @param left 左邊距,單位dp * @param right 右邊距,單位dp */ public void setPadding(int top, int bottom, int left, int right) { mPaddingTop = dip2px(top); mPaddingBottom = dip2px(bottom); mPaddingLeft = dip2px(left); mPaddingRight = dip2px(right); postInvalidate(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawColor(mBackgroundColor); drawContent(canvas); } private void drawContent(Canvas canvas) { if (mContentDataList.isEmpty()) { return; } for (int i = 0; i < mContentDataList.size(); i++) { String itemContent = mContentDataList.get(i); if (i == 0) { canvas.drawText(itemContent, mOneItemPoint.x, mOneItemPoint.y, mPaint); continue; } int y = mOneItemPoint.y + (mItemHeightSize * i); canvas.drawText(itemContent, mOneItemPoint.x, y, mPaint); } } private int sp2px(float spValue) { final float fontScale = getResources().getDisplayMetrics().scaledDensity; return (int) (spValue * fontScale + 0.5f); } private int dip2px(float dpValue) { float scale = getResources().getDisplayMetrics().density; return (int) (dpValue * scale + 0.5f); } public void setOnClickListener(OnClickListener listener) { this.mListener = listener; } public interface OnClickListener { void onItemDown(int position, String itemContent); void onItemMove(int position, String itemContent); void onItemUp(int position, String itemContent); } }
End