Android应用开发之android自定义控件之可以表示画笔大小的调整画笔size 的SeekBar
凌雪 2018-10-24 来源 :网络 阅读 1075 评论 0

摘要:本文将带你了解Android应用开发之android自定义控件之可以表示画笔大小的调整画笔size 的SeekBar,希望本文对大家学Android有所帮助。

本文将带你了解Android应用开发之android自定义控件之可以表示画笔大小的调整画笔size 的SeekBar,希望本文对大家学Android有所帮助。


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的画笔的颜色,这就是未滑过区域的颜色。代码如下:
?123456backgroundPath.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原生控件一样(具体方法我也不太记得了,到时要用到的时候问下度娘应该也挺快可以弄好的)。在最后会给出我当时写的源码,如果你在翻博客的时候翻到了这片博客,且对你有点用处的话给我点个赞,或者评论下让我听听您的高见。
?123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236/** *   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){ if="" int="" min=""   mmax="max;" public="" return=""   void="">mMax|min<mmin){ else="" if=""   int="" mmin="min;" mprogress="mMin;"   progress="" public="" return=""   void="">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);    } }</mmin){></mmin){>    

本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注职坐标移动开发之Android频道!

本文由 @凌雪 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式AI+学习就业服务平台 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved