Android開發 View_自定義快速索引側邊欄 SideBarView


前言

  一個實現快速索引的側邊欄,已經封裝完整,可以直接使用

使用它的一些注意點

     我是用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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM