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

猜你喜欢

转载自www.cnblogs.com/guanxinjing/p/12767497.html