android自定义控件之可以表示画笔大小的调整画笔size 的SeekBar

   作为一个也算是写过代码的人(虽然是个菜鸟),一直想写下自己的博客,之前由于上班的原因(其实是因为本人太懒)一直没机会写。现在辞完职休息了一个多星期后,就动手写写博客装装逼吧,也是对自己过去一年工作的总结。第一次写博客还是有点小激动的,写得不好也是情有可原(那能怎么办,我水平就这样偷笑)。废话说了一大堆,接下来就进入正文吧。

   当时项目中有个涂鸦画笔的功能,需要有个seekbar去动态调整涂鸦画笔的大小,同时还要能从seekbar表示出当前画笔的大小。效果图如下:

图中有绿色圆和绿色区域的控件就为自定义的seekbar控件。绿色圆的大小可以表示出当前涂鸦画笔的大小。滑动过的区域设置为绿色,未滑动过的区域设置为灰色。

下面介绍该控件的实现原理:


如图,图中黑色矩形框为自定义控件时的画布的大小,假设画布的宽高分别为W,H。让红色圆的上部 ( B点 )、下部(C点)分别于与画布的上边缘、下边缘相切,那么红色圆的直径就为H,可以算出红色圆的圆心坐标为(W-H/2,H/2),画出不移动的最大圆。A、B、C的坐标分别为(0,H/2)、(W-H/2,0)、(W-H/2,H)。然后新建路径backgroundPath,画三角形ABC,这时可以设置画路径backgroundPath的画笔的颜色,这就是未滑过区域的颜色。代码如下:

backgroundPath.reset();
backgroundPath.moveTo(mHeight/2,mHeight/2);
backgroundPath.lineTo(r,0);
backgroundPath.lineTo(r,mHeight);
backgroundPath.close();
canvas.drawPath(backgroundPath,backgroundPaint);

这就画出了基本的控件框架。接下来就是要画移动的黄色圆,这需要动态计算黄色圆的半径。


上图中的黄色圆是分别于直线AB、AC相切的,所以当我们左右移动黄色圆的时候黄色圆的圆心即G点的X坐标发生改变且其值是知道的(其实就是seekbar的值),所以G点坐标为(X,H/2)。由图形的几何关系很明显可以看出三角形AEG和三角形ADB是等比关系,所以可以算出黄色圆的半径EG   =AG/AB*BD(可以在三角形ABD 中根据勾股定理先算出AB 的长度)。这样知道了黄色圆的圆心坐标和半径,动态画出黄色圆就行了。

    最后是画出黄色圆滑动过的区域。跟上面的画backgroundPath路径一样,画三角形AEF这时设置的画笔颜色就是滑动过区域的颜色。到此这个自定义的seekbar就画完了。还有很重要的一步是给这个seekbar控件设置滑动监听事件,可以根据自己的需要实现自己的监听事件,这里就不在继续写下去了,毕竟不同的项目有不同需求,需要实现的监听也不一样。

    就这第一篇博客就写完了,当然这个控件还有很多可以完善的地方,比如可以加上其他一些属性,然后配置一下,让其在使用的时候可以直接在xml布局文件中直接设置属性值,就像使用android原生控件一样(具体方法我也不太记得了,到时要用到的时候问下度娘应该也挺快可以弄好的大笑)。在最后会给出我当时写的源码,如果你在翻博客的时候翻到了这片博客,且对你有点用处的话给我点个赞,或者评论下让我听听您的高见奋斗

/**
 * Created by lyh on 2017/11/7.
 */

public class MySeekBarView extends View {

    private Paint mPaint;//移动的外圈圆的画笔

    private Paint pressPaint;//滑动时的圆和滑动过的区域的画笔
    private Paint backgroundPaint;//背景圆的画笔

    private int mWidth;//控件的宽
    private int mHeight;//空间的高

    private Path pressPath;//用于控制滑动过的区域的颜色
    private Path backgroundPath;//用于控制背景颜色

    private int mMax = 200;//默认的最大值
    private int mMin = 0;//默认的最小值
    private int mProgress = 0;//当前的进度条大小

    private OnProgressChangedListener mProgressListener;//滑动监听接口

    public MySeekBarView(Context context) {
        super(context);
        init();
    }

    public MySeekBarView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public MySeekBarView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init(){

        mPaint = new Paint();
        mPaint.setColor(0xa8ffffff);
        mPaint.setDither(true);
        mPaint.setAntiAlias(true);
        mPaint.setStyle(Paint.Style.FILL);

        pressPaint = new Paint();
        pressPaint.setDither(true);
        pressPaint.setAntiAlias(true);
        pressPaint.setStyle(Paint.Style.FILL);
        pressPaint.setColor(0xff24c092);

        backgroundPaint = new Paint();
        backgroundPaint.setDither(true);
        backgroundPaint.setAntiAlias(true);
        backgroundPaint.setStyle(Paint.Style.FILL);
        backgroundPaint.setColor(0xff7a7979);

        pressPath = new Path();
        backgroundPath = new Path();
    }

    //设置移动外圈圆的颜色
    public void setmPaintColor(int color){
        mPaint.setColor(color);
    }

    //设置滑动过的区域的颜色
    public void setPressPaintColor(int color){
        pressPaint.setColor(color);
    }

    //设置背景区域的颜色
    public void setBackgroundPaint(int color){
        backgroundPaint.setColor(color);
    }

    public void setMax(int max){
        if (max>mMax|max<mMin){
            return;
        }
        mMax = max;
    }

    public int getMax(){
        return mMax;
    }

    public void setMin(int min){
        if (min>mMax|min<mMin){
            return;
        }
      mMin = min;
    }

    public int getMin(){
        return mMin;
    }

    public void setProgress(int progress){
        if (progress<mMin){
            mProgress = mMin;
        }else if (progress>mMax){
            mProgress = mMax;
        }else{
            mProgress = progress;
        }
        x = (int)((mProgress*1f/mMax) * (r-mHeight/2)) + mHeight/2;

        r1 = getR(x);
        if(mProgressListener != null) {
            mProgressListener.onProgressChanged(this, mProgress, false);
        }
        invalidate();
    }

    public int getProgress(){
        if (mMax!=0){
            mProgress = (int) ((x-mHeight/2)*1f/(r-mHeight/2) *mMax);
        }
        return mProgress;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:

                x = (int) event.getX();
                checkX();
                r1 = getR(x);
                if (mProgressListener!=null){
                    mProgressListener.onStartTrackingTouch(this);
                }

                break;
            case MotionEvent.ACTION_MOVE:

                x = (int) event.getX();
                checkX();
                r1 = getR(x);
                if (mProgressListener!=null){
                    mProgressListener.onProgressChanged(this,getProgress(),true);
                }
                break;

            case MotionEvent.ACTION_UP:

                x = (int) event.getX();
                checkX();
                r1 = getR(x);
                setProgress(getProgress());//点击时也改变进度值
                if (mProgressListener!=null){
                    mProgressListener.onStopTrackingTouch(this);
                }
                break;
        }
        invalidate();
        return true;
    }

    //限定x的范围
    private void checkX() {
        if (x <= mHeight/2){
            x = mHeight/2;
        }
        if (x > r){
            x = r;
        }
        if (x > r){
            x = r;
        }
    }

    //获得移动的圆的半径
    private int getR(int x){
//        int r = x*mHeight/2/this.r;
        int r = (int) ((x-mHeight/2)*1f/(mWidth-mHeight/2-mHeight/2) * mHeight/2);
        return  r;
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        requestLayout();
        invalidate();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    private int r =mHeight/2+1;//进度条的大小,默认设为不等于零,防止有些地方控件还没显示出来先调用了setProgress()方法导致除数为零异常
    private int r1;//移动时的圆的半径,可变
    private int x;//移动时的x坐标(距控件最左边的距离)

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        mHeight = bottom-top;
        mWidth = right-left;
        r = Math.abs(mWidth-mHeight/2);
        x = (int) (mProgress*1f/mMax*(r-mHeight/2)) + mHeight/2;
        r1 = getR(x);
        pressPath.moveTo(0,mHeight/2);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG|Paint.FILTER_BITMAP_FLAG));
        canvas.drawCircle(r,mHeight/2,mHeight/2,backgroundPaint);//外圈的背景圆

        if(backgroundPath!=null){//背景区域
            backgroundPath.reset();
            backgroundPath.moveTo(mHeight/2,mHeight/2);
            backgroundPath.lineTo(r,0);
            backgroundPath.lineTo(r,mHeight);
            backgroundPath.close();
            canvas.drawPath(backgroundPath,backgroundPaint);
        }

        if (pressPath!=null){//滑动过的区域
            pressPath.reset();
            pressPath.moveTo(mHeight/2,mHeight/2);
            pressPath.lineTo(x,mHeight/2-r1);
            pressPath.lineTo(x,mHeight/2+r1);
            pressPath.close();
            canvas.drawPath(pressPath,pressPaint);
        }
        if (r1==mHeight/2){
            canvas.drawCircle(x,mHeight/2,r1,pressPaint);//滑动时大小变化的圆
            canvas.drawCircle(x,mHeight/2,mHeight/2,mPaint);//滑动时大小不变得外圈圆
             }else{
            canvas.drawCircle(x,mHeight/2,mHeight/2,mPaint);//滑动时大小不变得外圈圆
            canvas.drawCircle(x,mHeight/2,r1,pressPaint);//滑动时大小变化的圆
        }

    }

    //设置滑动监听
    public void setOnProgressChangedListener(OnProgressChangedListener onProgressChangedListener){
        this.mProgressListener = onProgressChangedListener;
    }

    /**
     * 滑动监听接口
     */
    public interface OnProgressChangedListener {

        void onProgressChanged(MySeekBarView mySeekBar, int progress, boolean fromUser);

        void onStartTrackingTouch(MySeekBarView mySeekBar);

        void onStopTrackingTouch(MySeekBarView mySeekBar);
    }

}





评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值