一、效果图
本控件已上传Github,欢迎Star和Fork,项目地址:CircleWaterWaveView
二、设计思路
观察效果图,可以看出,该自定义控件由三个部分构成:外圆、内圆、正弦曲线。他们的关系如下图:
因为控件是动态的,所以我们需要一个线程去不停地绘制,所以我选择了SurfaceView来作为该控件地父类。该控件地核心是如何去绘制波浪,我采用如下的思路来进行内圆下部地绘制。利用内圆与正弦曲线地交集,来绘制。
核心代码如下:
/** * 绘制图像 * * @author luxun*/ private void drawCanvas(Canvas canvas) { if (canvas == null) return; //画背景圆圈 canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG)); canvas.drawCircle(mCenterPoint.x, mCenterPoint.y, mOutRadius, mOutCirclePaint); canvas.drawCircle(mCenterPoint.x, mCenterPoint.y, mRadius, mCirclePaint); if (mStart) { //计算正弦曲线的路径 int mH = mCenterPoint.y + mRadius - mCurrentHight; int length = 2 * mOutRadius; Path path = new Path(); path.moveTo(0, mH); for (int i = 0; i < length; i++) { int x = i; int y = (int) (Math.sin(Math.toRadians(x + mTranX) / amplitude) * mRadius / increase); path.lineTo(x, mH + y); } path.lineTo(length, mH); path.lineTo(length, mCenterPoint.y + mRadius); path.lineTo(0, mCenterPoint.y + mRadius); path.lineTo(0, mH); canvas.save();//保存画布状态 //这里与圆形取交集,除去正弦曲线多画的部分 Path pc = new Path(); pc.addCircle(mCenterPoint.x, mCenterPoint.y, mRadius, Path.Direction.CCW); canvas.clipPath(pc, Region.Op.INTERSECT);//切割画布 canvas.drawPath(path, mWaterPaint); //绘制文字 canvas.drawText(flowNum + "%", mCenterPoint.x, mCenterPoint.y + mTextSise / 2, mTextPaint); canvas.restore();//恢复画布状态 } }
三、性能优化
绘制线程如下:
/** * 绘制界面的线程 * * @author luxun */ private class RenderThread implements Runnable { @Override public void run() { // 不停绘制界面,这里是异步绘制,不采用外部通知开启绘制的方式,水波根据数据更新才会开始增长 while (isDrawing) { if (mWaterTaget > mCurrentHight) { mCurrentHight = mCurrentHight + mUpSpeed; if (mWaterTaget <= mCurrentHight) { mCurrentHight = mWaterTaget; } } if (mStart) { if (mTranX > mRadius) { mTranX = 0; } mTranX -= mWaterSpeed; } drawUI(); SystemClock.sleep(25);//控制刷新速率,减少cpu占用 } } }
通过为SurfaceHolder添加监听,来控制绘制线程。当控件被隐藏不在前台显示时,自动结束绘制线程,当控件显示在前台时,再次开启绘制。
@Override public void surfaceCreated(SurfaceHolder surfaceHolder) { isDrawing = true; new Thread(renderThread).start(); } @Override public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int width, int height) { int minLength = Math.min(width, height); mOutRadius = minLength / 2; mRadius = (int) (0.5 * (minLength - mOutStrokeWidth)); mCenterPoint = new Point(minLength / 2, minLength / 2); if (progress != 0) { setProgress(progress); } } @Override public void surfaceDestroyed(SurfaceHolder surfaceHolder) { isDrawing = false; }
四、属性化
部分设置属性,除了通过代码设置外,同时也加入了在XML文件中,直接以属性赋值的操作。
app:textColor="#00ff00"app:waterColor="#00ff00"app:strokeColor="#00ff00"app:backgroudColor="#00ff00"app:amplitude="1.0"[水波振幅]app:max="1000"app:progress="500"app:increase="6.0"[水波涨幅]app:upSpeed="3"[上涨速度]app:waterSpeed="8"[移动速度]app:strokeSize="4dp"app:textSize="20dp"
五、后记
代码已经上传Github,欢迎有兴趣的朋友去看看。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持VEVB武林网。
注:相关教程知识阅读请移步到Android开发频道。