软件编程
位置:首页>> 软件编程>> Android编程>> Android水波纹载入控件CircleWaterWaveView使用详解

Android水波纹载入控件CircleWaterWaveView使用详解

作者:一语成空  发布时间:2021-10-27 23:06:58 

标签:Android,水波纹

一、效果图

Android水波纹载入控件CircleWaterWaveView使用详解

本控件已上传Github,欢迎Star和Fork,项目地址:CircleWaterWaveView

二、设计思路

观察效果图,可以看出,该自定义控件由三个部分构成:外圆、内圆、正弦曲线。他们的关系如下图:

Android水波纹载入控件CircleWaterWaveView使用详解

因为控件是动态的,所以我们需要一个线程去不停地绘制,所以我选择了SurfaceView来作为该控件地父类。该控件地核心是如何去绘制波浪,我采用如下的思路来进行内圆下部地绘制。利用内圆与正弦曲线地交集,来绘制。 

Android水波纹载入控件CircleWaterWaveView使用详解

核心代码如下:


/**
* 绘制图像
*
* @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,欢迎有兴趣的朋友去看看。

来源:https://blog.csdn.net/lx578111527/article/details/52797947

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com