凌雪
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
您输入的评论内容中包含违禁敏感词
我知道了

请输入正确的手机号码
请输入正确的验证码
您今天的短信下发次数太多了,明天再试试吧!
我们会在第一时间安排职业规划师联系您!
您也可以联系我们的职业规划师咨询:
版权所有 职坐标-一站式AI+学习就业服务平台 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
沪公网安备 31011502005948号