一、效果图
本控件已上传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,欢迎有兴趣的朋友去看看。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持亿速云。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。