自定义竖向SeekBar (VerticalSeekBar)

 

最近在项目需要用到用到一个垂直方向的seekbar,在网上找了下都是通过修改系统seekbar的样式以及触摸方法来实现,实现起来也比较麻烦

所以就想着自己实现,现在给大家分享一下我的实现思路

首先从获取xml自定义属性

public VerticalSeekBar(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.VerticalSeekBar, defStyleAttr, 0);
    intrinsicHeight = (int) a.getDimension(R.styleable.VerticalSeekBar_thumbSize, -1);  //图片大小   此处保持矩形为正方    形所以设置成宽高一样
    intrinsicWidth = (int) a.getDimension(R.styleable.VerticalSeekBar_thumbSize, -1);   //图片大小
    progress=a.getInteger(R.styleable.VerticalSeekBar_progress,30);
    maxProgress=a.getInteger(R.styleable.VerticalSeekBar_max,100);
    orientation=a.getBoolean(R.styleable.VerticalSeekBar_orientation,false);
    unSelectColor = a.getColor(R.styleable.VerticalSeekBar_barbg,  0xcc888888);  //进度条背景色
    selectColor = a.getColor(R.styleable.VerticalSeekBar_progressbg,  getContext().getResources().getColor(R.color.main_bg_blue)); //进度条颜色
    a.recycle();
    init(context, attrs, defStyleAttr);
}

 根据获取的属性初始化控件

/**
 * 初始化控件
 * @param context
 */
private void init(Context context) {
    this.context = context;
    paint = new Paint();
    iamgePaint=new Paint();
    mThumb = BitmapFactory.decodeResource(getResources(), R.drawable.seekbarring);
    if (intrinsicHeight==-1) {//没有设置则使用图片本身大小
        intrinsicHeight = mThumb.getHeight();
        intrinsicWidth = mThumb.getWidth();
    }
    mDestRect = new RectF(0, 0, intrinsicWidth, intrinsicHeight);
    mInnerProgressWidthPx = Dp2PxUtils.dip2px(context, mInnerProgressWidth);
}

此处我用了一个一圆圈图片作为seek的指针实际上可以通过自己绘制圆实现(偷了个懒)

@Override
protected void onDraw(Canvas canvas) {
    if (!orientation ) { 判断滑动方向
        locationY = (int) (intrinsicHeight * 0.5f + (maxProgress - progress) * (height - intrinsicHeight) / maxProgress);
    } else {
        locationY = (int) (intrinsicHeight * 0.5f + (progress) * (height - intrinsicHeight) / maxProgress);
    }
    paint.setColor(!orientation  ? unSelectColor : selectColor);
    canvas.drawRect(width / 2 - mInnerProgressWidthPx / 2, mDestRect.height() / 2, width / 2 + mInnerProgressWidthPx / 2, locationY, paint);//绘制背景
    paint.setColor(!orientation  ? selectColor : unSelectColor);
    canvas.drawRect(width / 2 - mInnerProgressWidthPx / 2, locationY, width / 2 + mInnerProgressWidthPx / 2, height - mDestRect.height() / 2, paint);//绘制进度
    canvas.save();
    canvas.translate(width / 2 - mDestRect.width() / 2, locationY - mDestRect.height() / 2);
    canvas.drawBitmap(mThumb, null, mDestRect, iamgePaint);  //绘制指针
    canvas.restore();
    super.onDraw(canvas);
}

 上面图形已经绘制完成接下来处理触摸事件

@Override
public boolean onTouchEvent(MotionEvent event) {
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            //判断点击点是否在圈圈上
            isInnerClick = isClickthum(event);
            if (isInnerClick) {
                if (listener != null) {
                    listener.onStart(this, progress);
                }
            }
            downX = event.getX();
            downY = event.getY();

            break;
        case MotionEvent.ACTION_MOVE:
            if (isInnerClick) {//点击在指针上才算有效点击 才能滑动
                locationY = (int) event.getY();
                fixLocationY();
                //计算进度值
                progress = (int) (maxProgress - (locationY - intrinsicHeight * 0.5) / (height - intrinsicHeight) * maxProgress);
                if (orientation) {
                    progress = maxProgress - progress;
                }
                downY = event.getY();
                downX = event.getX();
                if (listener != null) {
                    listener.onProgress(this, progress);
                }
                invalidate();
            }
            break;
        case MotionEvent.ACTION_UP:
            if (isInnerClick) {
                if (listener != null) {  //手指松开表示滑动停止
                    listener.onStop(this, progress);
                }
            }
            break;
    }
    return true;
}
此处只看处理步骤。有部分判断代码没有贴出,会在后面给出完整代码

最后资源回收

@Override
protected void onDetachedFromWindow() {
    if (mThumb != null) {
        mThumb.recycle();
    }
    super.onDetachedFromWindow();
}

 

至此自定义竖向seekbar大功告成

完整代码

package com.zwh.myapplication;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;


public class VerticalSeekBar extends View {
    private Context context;
    private int height;
    private int width;
    private Paint paint;
    private Paint iamgePaint;
    private int maxProgress = 100;   //进图条最大值
    private int progress = 30;  //当前进度

    protected Bitmap mThumb;  //seekbar中的头部圆圈
    private int intrinsicHeight;   //圆圈高
    private int intrinsicWidth;   //圆圈宽
    private boolean isInnerClick;
    private float downX;
    private float downY;

    private int locationX;
    private int locationY = -1;

    private int mInnerProgressWidth = 4;
    private int mInnerProgressWidthPx;

    private int unSelectColor ;
    private RectF mDestRect;
    /**
     * 滑动方向,
     * false代表从下向上滑
     * true代表从上向下滑
     */
    private boolean orientation=false;

    /**
     * 设置未选中的颜色
     *
     * @param uNSelectColor
     */
    public void setUnSelectColor(int uNSelectColor) {
        this.unSelectColor = uNSelectColor;
    }

    /**
     * 设置滑动方向,
     * false代表从下向上滑
     * true代表从上向下滑
     * @param orientation
     */
    public void setOrientation(boolean orientation) {
        this.orientation = orientation;
        invalidate();
    }

    private int selectColor ;

    /**
     * 设置选中线条的颜色
     *
     * @param selectColor
     */
    public void setSelectColor(int selectColor) {
        this.selectColor = selectColor;
    }

    /**
     * 设置进度条的宽度 单位是px
     *
     * @param mInnerProgressWidthPx
     */
    public void setmInnerProgressWidthPx(int mInnerProgressWidthPx) {
        this.mInnerProgressWidthPx = mInnerProgressWidthPx;
    }

    /**
     * 设置进度条的宽度 ,单位是dp;默认是4db
     *
     * @param mInnerProgressWidth
     */
    public void setmInnerProgressWidth(int mInnerProgressWidth) {
        this.mInnerProgressWidth = mInnerProgressWidth;
            //此出有一个dp转px的方法我就不贴出来了项目上相信大家都有用到自行替换
        mInnerProgressWidthPx = Dp2PxUtils.dip2px(context, mInnerProgressWidth);
    }


    /**
     * 设置图片
     *
     * @param id
     */
    public void setThumb(int id) {

        mThumb = BitmapFactory.decodeResource(getResources(), id);
        intrinsicHeight = mThumb.getHeight();
        intrinsicWidth = mThumb.getWidth();
        mDestRect.set(0, 0, intrinsicWidth, intrinsicHeight);
        invalidate();
    }

    /**
     * 设置滑动图片的大小 单位是dp
     *
     * @param width
     * @param height
     */
    public void setThumbSize(int width, int height) {
        setThumbSizePx(Dp2PxUtils.dip2px(context, width), Dp2PxUtils.dip2px(context, height));
    }

    /**
     * 设置滑动图片的大小 单位是px
     *
     * @param width
     * @param height
     */
    public void setThumbSizePx(int width, int height) {
        intrinsicHeight = width;
        intrinsicWidth = height;
        mDestRect.set(0, 0, width, height);
        invalidate();
    }



    public VerticalSeekBar(Context context) {
        this(context,null,0);

    }

    public VerticalSeekBar(Context context, AttributeSet attrs) {
        this(context,attrs,0);
    }



    public VerticalSeekBar(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.VerticalSeekBar, defStyleAttr, 0);
        intrinsicHeight = (int) a.getDimension(R.styleable.VerticalSeekBar_thumbSize, -1);  //图片大小   此处保持矩形为正方形所以设置成宽高一样
        intrinsicWidth = (int) a.getDimension(R.styleable.VerticalSeekBar_thumbSize, -1);   //图片大小
        progress=a.getInteger(R.styleable.VerticalSeekBar_progress,30);
        maxProgress=a.getInteger(R.styleable.VerticalSeekBar_max,100);
        orientation=a.getBoolean(R.styleable.VerticalSeekBar_orientation,false);
        unSelectColor = a.getColor(R.styleable.VerticalSeekBar_barbg,  0xcc888888);  //进度条背景色
        selectColor = a.getColor(R.styleable.VerticalSeekBar_progressbg,  getContext().getResources().getColor(R.color.main_bg_blue)); //进度条颜色
        a.recycle();
        init(context);
    }

    /**
     * 初始化控件
     * @param context
     */
    private void init(Context context) {
        this.context = context;
        paint = new Paint();
        iamgePaint=new Paint();
        mThumb = BitmapFactory.decodeResource(getResources(), R.drawable.seekbarring);
        if (intrinsicHeight==-1) {
            intrinsicHeight = mThumb.getHeight();
            intrinsicWidth = mThumb.getWidth();
        }
        mDestRect = new RectF(0, 0, intrinsicWidth, intrinsicHeight);
        mInnerProgressWidthPx = Dp2PxUtils.dip2px(context, mInnerProgressWidth);
    }


    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        height = getMeasuredHeight();
        width = getMeasuredWidth();
        if (locationY == -1) {
            locationX = width / 2;
            locationY = height / 2;

        }

    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                //判断点击点是否在圈圈上
                isInnerClick = isClickthum(event);
                if (isInnerClick) {
                    if (listener != null) {
                        listener.onStart(this, progress);
                    }
                }
                downX = event.getX();
                downY = event.getY();

                break;
            case MotionEvent.ACTION_MOVE:
                if (isInnerClick) {//点击在指针上才算有效点击 才能滑动
                    locationY = (int) event.getY();
                    fixLocationY();
                    //计算进度值
                    progress = (int) (maxProgress - (locationY - intrinsicHeight * 0.5) / (height - intrinsicHeight) * maxProgress);
                    if (orientation) {
                        progress = maxProgress - progress;
                    }
                    downY = event.getY();
                    downX = event.getX();
                    if (listener != null) {
                        listener.onProgress(this, progress);
                    }
                    invalidate();
                }
                break;
            case MotionEvent.ACTION_UP:
                if (isInnerClick) {
                    if (listener != null) {  //手指松开表示滑动停止
                        listener.onStop(this, progress);
                    }
                }
                break;
        }
        return true;
    }

    private void fixLocationY() {//留出显示图标半径位置
        if (locationY <= intrinsicHeight / 2) {
            locationY = intrinsicHeight / 2;
        } else if (locationY >= height - intrinsicHeight / 2) {
            locationY = height - intrinsicHeight / 2;
        }
    }

    /**
     * 是否点击了图片
     *
     * @param event
     * @return
     */
    private boolean isClickthum(MotionEvent event) {
        return event.getX() >= width / 2 - intrinsicWidth / 2 -20&& event.getX() <= width / 2 + intrinsicWidth / 2+20 && event.getY() >= locationY - intrinsicHeight / 2-20 && event.getY() <= locationY + intrinsicHeight / 2+20;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (!orientation ) {
            locationY = (int) (intrinsicHeight * 0.5f + (maxProgress - progress) * (height - intrinsicHeight) / maxProgress);
        } else {
            locationY = (int) (intrinsicHeight * 0.5f + (progress) * (height - intrinsicHeight) / maxProgress);
        }
        paint.setColor(!orientation  ? unSelectColor : selectColor);
        canvas.drawRect(width / 2 - mInnerProgressWidthPx / 2, mDestRect.height() / 2, width / 2 + mInnerProgressWidthPx / 2, locationY, paint);
        paint.setColor(!orientation  ? selectColor : unSelectColor);
        canvas.drawRect(width / 2 - mInnerProgressWidthPx / 2, locationY, width / 2 + mInnerProgressWidthPx / 2, height - mDestRect.height() / 2, paint);
        canvas.save();
        canvas.translate(width / 2 - mDestRect.width() / 2, locationY - mDestRect.height() / 2);
        canvas.drawBitmap(mThumb, null, mDestRect, iamgePaint);
        canvas.restore();
        super.onDraw(canvas);
    }

    public void setProgress(int progress) {
        if (height == 0) {
            height = getMeasuredHeight();
        }

        this.progress = progress;

        invalidate();
    }

    public int getProgress() {
        return progress;
    }

    @Override
    protected void onDetachedFromWindow() {
        if (mThumb != null) {
            mThumb.recycle();
        }
        super.onDetachedFromWindow();
    }


    public void setMaxProgress(int maxProgress) {
        this.maxProgress = maxProgress;
    }

    public int getMaxProgress() {
        return maxProgress;
    }

    private SlideChangeListener listener;

    public void setOnSlideChangeListener(SlideChangeListener listener) {
        this.listener = listener;
    }

    //添加监听接口
    public interface SlideChangeListener {
        /**
         * 开始滑动
         *
         * @param slideView
         * @param progress
         */
        void onStart(VerticalSeekBar slideView, int progress);

        /**
         * 滑动过程中
         *
         * @param slideView
         * @param progress
         */
        void onProgress(VerticalSeekBar slideView, int progress);

        /**
         * 停止滑动
         *
         * @param slideView
         * @param progress
         */
        void onStop(VerticalSeekBar slideView, int progress);
    }

}

 

attrs中的自定义属性

 




    
        
        
        
        
        
        
        
        
        
        

    

 

你可能感兴趣的:(自定义竖向SeekBar (VerticalSeekBar))