seekBar的分段显示

自定义seekBar的分段显示,这个以后也会用的到。下面的这个代码是自己在网上搜的(源链接:http://blog.csdn.net/lyj1005353553/article/details/77099578),然后自己把需要添加注释的代码都添加了注释,方便大家理解,自己也做了一些小改动现在可以直接拿去用,用的时候只需要在XML文件和代码中写几句代码就可以了。

首先需要在attr文件中添加

<declare-styleable name="RangeSliderView">
  <attr name="rangeCount" format="integer"/>
  <attr name="filledColor" format="color"/>
  <attr name="emptyColor" format="color"/>
  <attr name="barHeightPercent" format="float"/>
  <attr name="circleRadiusPercent" format="float"/>
  <attr name="sliderRadiusPercent" format="float"/>
</declare-styleable>
  1. XML文件中配置属性,需要在根布局中声明xmlns:rsv=”http://schemas.android.com/apk/res-auto”
    rsv:emptyColor=”#自定义” //一级背景颜色
    rsv:filledColor=”#自定义” //二级背景颜色
  2. Activity中
    rangeSliderBar = (RangeSliderBar) findViewById(R.id.rsv_custom);
    rangeSliderBar.setRangeCount(mDatas.length); //设置分段的个数
    rangeSliderBar.setContext(this);
    rangeSliderBar.setNums(mDatas); //设置分段的数据
    //实现的接口
    rangeSliderBar.setOnSelectRangeBarListener(new RangeSliderBar.OnSelectRangeBarListener() {
    @Override
    public void OnSelectRange(int rangeNum) {
    Toast.makeText(MainActivity.this,
    “我现在的位置是” + rangeNum,
    Toast.LENGTH_SHORT).show();
    }
    });

    自定义控件完整代码:

public class RangeSliderBar extends View {

    private static final String TAG = "RangeSliderBar";
    private Context context;
    /**
    画笔的默认的宽度
    */
    private static final int DEFAULT_PAINT_STROKE_WIDTH = 8;
    /**
    seekBar的默认二级背景
    */
    private static final int DEFAULT_FILLED_COLOR = Color.parseColor("#FFA500");
    /**
    seekBar的默认一级背景
    */
    private static final int DEFAULT_EMPTY_COLOR = Color.parseColor("#ff0000");
    /**
     * rangebar粗细
     */
    private static final float DEFAULT_BAR_HEIGHT_PERCENT = 0.10f;

    /**
     * 设置自定义seekBar的长度
     * 这个长度要与传进来数组的长度一致
     */
    private static final int DEFAULT_RANGE_COUNT = 6;

    /**
     * rangebar高度
     */
    private static final int DEFAULT_HEIGHT_IN_DP = 90;

    /**
     * seekBar的画笔
     */
    protected Paint paint;
     /**
     * 分段显示的画笔
     */
    protected Paint mPaint;
    /**
     * 当前的索引位置
     */
    private int currentIndex;
    /**
     * 当前的X坐标
     */
    private float currentSlidingX;
    /**
     * 当前的Y坐标
     */
    private float currentSlidingY;
     /**
     * 具体分段显示的数值
     */
    private int[] circlePositions;

    /**
     * 分段显示的距离数组
     */
    private float[] circlePositions2 = new float[DEFAULT_RANGE_COUNT];
    /**
     * 填充颜色
     */
    private int filledColor = DEFAULT_FILLED_COLOR;
    /**
     * 空白颜色
     */
    private int emptyColor = DEFAULT_EMPTY_COLOR;

    private float barHeightPercent = DEFAULT_BAR_HEIGHT_PERCENT;
    /**
     * 分段显示的数量
     */
    private int rangeCount = DEFAULT_RANGE_COUNT;

    private int barHeight, locationY;
    private float downX;
    private float downY;

    /**
     * seekBar滑块的图片
     */
    private Bitmap bitmap_point;

    private int layoutHeight;
//    private boolean mPopupStyle;//是否显示pop

    private PopupWindow mPopup;
    View popView;
    TextView tv;
    int indexNum; //位置数值
    private int[] mPosition;

    public RangeSliderBar(Context context) {
        this(context, null);
        this.context = context;
        initPop();
    }

    public RangeSliderBar(Context context, AttributeSet attrs) {
        this(context, attrs, -1);
        this.context = context;
        initPop();
    }

    public void setContext(Context context) {
        this.context = context;
    }


    public void setShowPopText(String str) {
        tv.setText(str);
    }

    void initPop() {
        mPosition = new int[2];
//        popView = LayoutInflater.from(context).inflate(R.layout.seekbar_pop, null);
//        mPopup = new PopupWindow(popView, popView.getWidth(), popView.getHeight(), true);
//        tv = (TextView) popView.findViewById(R.id.tv_showtxt);
    }


    public RangeSliderBar(Context context, AttributeSet attrs, int
            defStyleAttr) {
        super(context, attrs, defStyleAttr);
        //自定义属性
        if (attrs != null) {
            TypedArray a = context.obtainStyledAttributes(attrs, R.styleable
                    .RangeSliderView);
            TypedArray sa = context.obtainStyledAttributes(attrs, new
                    int[]{android.R.attr.layout_height});
            try {
                layoutHeight = sa.getLayoutDimension(
                        0, 0);
                rangeCount = a.getInt(
                        R.styleable.RangeSliderView_rangeCount,
                        DEFAULT_RANGE_COUNT);
                filledColor = a.getColor(
                        R.styleable.RangeSliderView_filledColor,
                        DEFAULT_FILLED_COLOR);
                emptyColor = a.getColor(
                        R.styleable.RangeSliderView_emptyColor,
                        DEFAULT_EMPTY_COLOR);
                barHeightPercent = a.getFloat(
                        R.styleable.RangeSliderView_barHeightPercent,
                        DEFAULT_BAR_HEIGHT_PERCENT);
                barHeightPercent = a.getFloat(
                        R.styleable.RangeSliderView_barHeightPercent,
                        DEFAULT_BAR_HEIGHT_PERCENT);
            } finally {
                a.recycle();
                sa.recycle();
            }
        }
        setBarHeightPercent(barHeightPercent);
        setRangeCount(rangeCount);
        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setStrokeWidth(DEFAULT_PAINT_STROKE_WIDTH);
        paint.setStyle(Paint.Style.FILL_AND_STROKE);

        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setColor(Color.WHITE);
        mPaint.setTextSize(30);
//        mPaint.setAntiAlias(true);
        //自定义控件UI的监听器
        getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver
                .OnPreDrawListener() {
            @Override
            public boolean onPreDraw() {
                getViewTreeObserver().removeOnPreDrawListener(this);

                // Update radius after we got new height
                updateRadius(getHeight());
                // Compute drawing position again
                preComputeDrawingPosition();
                // Ready to draw now
                return true;
            }
        });
        //设置默认选中第二个位置
        currentIndex = 2;
//        setShowPopText(circlePositions[currentIndex] + "");
    }


    private void updateRadius(int height) {
        barHeight = (int) (height * barHeightPercent);
        locationY = barHeight + DEFAULT_HEIGHT_IN_DP; //Y位置
    }

    /**
     * 设置分段显示的数据
     */
    public void setNums(int[] nums) {
        this.circlePositions = nums;
    }

    /**
     * 设置分段显示的长度,必须与数据的大小一致!
     * @param rangeCount
     */
    public void setRangeCount(int rangeCount) {
        if (rangeCount < 2) {
            throw new IllegalArgumentException("rangeCount must be >= 2");
        }
        this.rangeCount = rangeCount;
    }


    public void setBarHeightPercent(float percent) {
        if (percent <= 0.0 || percent > 1.0) {
            throw new IllegalArgumentException("Bar height percent must be in" +
                    " (0, 1]");
        }
        this.barHeightPercent = percent;
    }


    /**
     * Perform all the calculation before drawing, should only run once
     * 计算各分段显示的位置,这里采取均匀分开!
     */
    private void preComputeDrawingPosition() {
        int w = getWidthWithPadding();
        int h = getHeightWithPadding();

        initPop();
        /** Space between each circle */
        int spacing = w / rangeCount;
        /** Center vertical */
        int y = getPaddingTop() + h / 2;
        currentSlidingY = y;
        int x = getPaddingLeft() + (spacing / 2);
        /** Store the position of each circle index */
        for (int i = 0; i < circlePositions.length; ++i) {
            circlePositions2[i] = x;
            Log.e("--------->", "circlePositions[i]==" + circlePositions[i]);
            if (i == currentIndex) {
                currentSlidingX = x;
            }
            //这里采用均匀距离,若是想根据值来显示距离,这里需要自己修改!
            x += spacing;
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight
                (heightMeasureSpec));
    }

    /**
     * Measures height according to the passed measure spec
     *
     * @param measureSpec int measure spec to use
     * @return int pixel size
     */
    private int measureHeight(int measureSpec) {
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);
        int result;
        if (specMode == MeasureSpec.EXACTLY) {
            result = specSize;
        } else {
            final int height;
            if (layoutHeight == ViewGroup.LayoutParams.WRAP_CONTENT) {
                height = dpToPx(getContext(), DEFAULT_HEIGHT_IN_DP);
            } else if (layoutHeight == ViewGroup.LayoutParams.MATCH_PARENT) {
                height = getMeasuredHeight();
            } else {
                height = layoutHeight;
            }
            result = height + getPaddingTop() + getPaddingBottom() + (2 *
                    DEFAULT_PAINT_STROKE_WIDTH);
            if (specMode == MeasureSpec.AT_MOST) {
                result = Math.min(result, specSize);
            }
        }
        return result;
    }

    /**
     * Measures width according to the passed measure spec
     *
     * @param measureSpec int measure spec to use
     * @return int pixel size
     */
    private int measureWidth(int measureSpec) {
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);
        int result;
        if (specMode == MeasureSpec.EXACTLY) {
            result = specSize;
        } else {
            result = specSize + getPaddingLeft() + getPaddingRight() + (2 *
                    DEFAULT_PAINT_STROKE_WIDTH);
            if (specMode == MeasureSpec.AT_MOST) {
                result = Math.min(result, specSize);
            }
        }
        return result;
    }

    private void updateCurrentIndex() {
        float min = Float.MAX_VALUE;
        int j = 0;
        /** Find the closest to x */
        for (int i = 0; i < rangeCount; ++i) {
            float dx = Math.abs(currentSlidingX - circlePositions2[i]);
            if (dx < min) {
                min = dx;
                j = i;
            }
        }
        currentIndex = j;
        /** Correct position */
        currentSlidingX = circlePositions2[j];
        Log.e("updateCurrentIndex==", "currentSlidingX=" + currentSlidingX);
        downX = currentSlidingX;
        downY = currentSlidingY;
        invalidate();
    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float y = event.getY();
        float x = event.getX();
        final int action = event.getActionMasked();
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                downX = x;
                downY = y;
                this.getLocationOnScreen(mPosition);
//                mPopup.showAsDropDown(this, (int) downX, -170 - bitmap_point.getHeight());
                break;

            case MotionEvent.ACTION_MOVE:
                if (x >= circlePositions2[0] && x <=
                        circlePositions2[rangeCount - 1]) {
                    currentSlidingX = x;
                    currentSlidingY = y;
                    invalidate();
                }
                break;

            case MotionEvent.ACTION_UP:
                currentSlidingX = x;
                currentSlidingY = y;
//                mPopup.dismiss();
                updateCurrentIndex();
                invalidate();
                if (onSelectRangeBarListener != null) {
                    int range = circlePositions[currentIndex];
//                    setShowPopText(range + "");
                    onSelectRangeBarListener.OnSelectRange(range);
                }
                break;
        }
        return true;
    }


    private void drawDefaultCircle(Canvas canvas) {
        paint.setColor(emptyColor);
        int h = getHeightWithPadding();
        int y = getPaddingTop() + (h >> 1);
        for (int i = 0; i < circlePositions.length; ++i) {
            //每个对应数字下画竖线
            /**
             * 画线参数:startX,startY,endX,endY
             * 画文字参数:文字,起始坐标X,起始坐标Y
             */
            canvas.drawLine(circlePositions2[i], y + barHeight + 5, circlePositions2[i], y + barHeight + 20, mPaint);
            canvas.drawText(circlePositions[i] + "s", circlePositions2[i] - 10, y + barHeight + 50, mPaint);
        }
    }

    private void drawSlidRangeCircle(Canvas canvas, int x0, int spc) {
        paint.setColor(filledColor);
        int h = getHeightWithPadding();
        int y = getPaddingTop() + (h >> 1);
        for (int i = 0; i < circlePositions.length; ++i) {
            canvas.drawText(circlePositions[i] + "", circlePositions2[i] - 10, y + barHeight + 50, mPaint);
        }
    }


    /**
     * 画rangebar
     *
     * @param canvas
     * @param from
     * @param to
     * @param color
     */
    private void drawBar(Canvas canvas, int from, int to, int color) {
        paint.setColor(color);
        int half = (barHeight >> 1);
        int y = getPaddingTop() + barHeight + DEFAULT_HEIGHT_IN_DP; //设置bar位置

        /**
         * 画长方形
         */
//        canvas.drawRect(from, y - half, to, y + half, paint);
        /**
         * 画圆角矩形
         */
//        RectF oval3 = new RectF(from, y - half, to, y + half);
//        canvas.drawRoundRect(oval3, 3, 3, paint);//画圆角矩形
        /**
         * 画线
         */
        canvas.drawLine(from, y, to, y, paint);
    }

    private int getViewWidth(View v) {
        int w = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
        int h = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
        v.measure(w, h);
        return v.getMeasuredWidth();
    }

    private int getViewHeight(View v) {
        int w = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
        int h = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
        v.measure(w, h);
        return v.getMeasuredHeight();
    }

    public void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int w = getWidthWithPadding();
        int spacing = w / rangeCount;
        int border = (spacing >> 1);
        int x0 = getPaddingLeft() + border;
        if (mPopup != null) {
            try {
                this.getLocationOnScreen(mPosition);
                mPopup.update((int) downX, -170, getViewWidth(popView)
                        , getViewHeight(popView));
            } catch (Exception e) {
            }
        }

//        bitmap_point = BitmapFactory.decodeResource(getResources(), AppMgr.iDraw("dot_chart"));
        bitmap_point = BitmapFactory.decodeResource(getResources(), R.mipmap.seekbar_yelloe);
        /** Draw empty bar 画一级背景*/
        drawBar(canvas, (int) circlePositions2[0], (int)
                circlePositions2[rangeCount - 1], emptyColor);
        /** Draw filled bar 画二级背景*/
        drawBar(canvas, x0, (int) currentSlidingX, filledColor);

        int bitmap_pointHeight = bitmap_point.getHeight();
        Log.e(TAG,bitmap_pointHeight+""); //56
        //seekBar滑块的位置,这里根据自己的需要进行调整
        //画移动背景图
        canvas.drawBitmap(bitmap_point, (int) currentSlidingX - 30, x0 , null);
        /** Draw the selected range circle */
        paint.setColor(filledColor);
        drawDefaultCircle(canvas);
//        drawSlidRangeCircle(canvas, (int) currentSlidingX, spacing);
    }


    public int getHeightWithPadding() {
        return getHeight() - getPaddingBottom() - getPaddingTop();
    }

    public int getWidthWithPadding() {
        return getWidth() - getPaddingLeft() - getPaddingRight();
    }


    @Override
    public Parcelable onSaveInstanceState() {
        Parcelable superState = super.onSaveInstanceState();
        SavedState ss = new SavedState(superState);
        ss.saveIndex = this.currentIndex;
        return ss;
    }

    @Override
    public void onRestoreInstanceState(Parcelable state) {
        if (!(state instanceof SavedState)) {
            super.onRestoreInstanceState(state);
            return;
        }
        SavedState ss = (SavedState) state;
        super.onRestoreInstanceState(ss.getSuperState());
        this.currentIndex = ss.saveIndex;
    }
    /**
     * 保存状态的类,横竖屏切换的时候用来保存切换之前的状态
     */
    static class SavedState extends BaseSavedState {
        int saveIndex;

        SavedState(Parcelable superState) {
            super(superState);
        }

        private SavedState(Parcel in) {
            super(in);
            this.saveIndex = in.readInt();
        }

        @Override
        public void writeToParcel(Parcel out, int flags) {
            super.writeToParcel(out, flags);
            out.writeInt(this.saveIndex);
        }

        //required field that makes Parcelables from a Parcel
        public static final Creator<SavedState> CREATOR =
                new Creator<SavedState>() {
                    public SavedState createFromParcel(Parcel in) {
                        return new SavedState(in);
                    }

                    public SavedState[] newArray(int size) {
                        return new SavedState[size];
                    }
                };
    }

    /**
     * Helper method to convert dp to pixel
     *
     * @param context
     * @param dp
     * @return
     */
    static int dpToPx(final Context context, final float dp) {
        return (int) (dp * context.getResources().getDisplayMetrics().density);
    }


    OnSelectRangeBarListener onSelectRangeBarListener;
    /**
     * 自定义接口,提供接口让外部实现处理自己的逻辑
     */
    public interface OnSelectRangeBarListener {
        /**
         * 实现接口需要实现的方法,这里的参数rangeNum就是seekBar滑动停止后的位置所对应的数据
         */
        void OnSelectRange(int rangeNum);
    }

    public void setOnSelectRangeBarListener(OnSelectRangeBarListener
                                                    onSelectRangeBarListener) {
        this.onSelectRangeBarListener = onSelectRangeBarListener;
    }
}

最后再次注明一下源链接:http://blog.csdn.net/lyj1005353553/article/details/77099578

猜你喜欢

转载自blog.csdn.net/liuxiaopang520/article/details/77676245