android多个水波球,Android自定义View——贝塞尔曲线实现水波纹进度球
效果演示 实现原理想要了解基础的水波纹实现效果,可以在博客的自定义View专题找到,其实现原理如下利用贝塞尔曲线绘制屏幕外和屏幕内的sin曲线利用path将sin曲线的左下角和右下角连接起来成为一块区域通过不断的平移sin曲线,然后平移完一个周期则重新回到原点 实现过程绘制实现的步骤如下裁剪画布为圆形绘制圆形边框绘制波浪区域绘制进度文字自动增长进度前提准备我们创建一个View继承自View,并声明
效果演示
实现原理
想要了解基础的水波纹实现效果,可以在博客的自定义View专题找到,其实现原理如下
利用贝塞尔曲线绘制屏幕外和屏幕内的sin曲线
利用path将sin曲线的左下角和右下角连接起来成为一块区域
通过不断的平移sin曲线,然后平移完一个周期则重新回到原点
实现过程
绘制实现的步骤如下
裁剪画布为圆形
绘制圆形边框
绘制波浪区域
绘制进度文字
自动增长进度
前提准备
我们创建一个View继承自View,并声明我们想要的变量和初始化画笔
public class WaveView extends View {
//View的宽高
private int width;
private int height;
//View的画笔
private Paint wavePaint;
private Paint textPaint;
private Paint circlePaint;
//波浪的路径
private Path path;
//sin曲线的长度:一个周期长度
private int cycle = 160;
//每次平移的长度,为四分之一个周期
private int translateX = cycle / 4;
//sin曲线振幅的高度
private int waveHeight = 80;
//sin曲线的起点坐标
private Point startPoint;
//当前波浪的进度
private int progress = 0;
//当前波浪的速度
private int waveSpeech = 150;
//是否启用了自动增长进度
private boolean isAutoIncrease = false;
public WaveView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
initPaint(context);
}
public WaveView(Context context) {
super(context);
initPaint(context);
}
private void initPaint(Context context) {
path = new Path();
wavePaint = new Paint();
wavePaint.setAntiAlias(true);
wavePaint.setStyle(Paint.Style.FILL);
wavePaint.setColor(Color.parseColor("#1998FA"));
circlePaint = new Paint();
circlePaint.setStrokeWidth(5);
circlePaint.setStyle(Paint.Style.STROKE);
circlePaint.setAntiAlias(true);
circlePaint.setColor(Color.parseColor("#1998FA"));
textPaint = new Paint();
textPaint.setAntiAlias(true);
textPaint.setTextSize(50);
textPaint.setColor(Color.BLUE);
}
}
测量大小
重写onMeasure()来指定我们的View的大小,由于我们是一个圆形,所以取的值是宽高的最小值
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
width = measureSize(400, widthMeasureSpec);
height = measureSize(400, heightMeasureSpec);
width = Math.min(width, height);
height = Math.min(width, height);
setMeasuredDimension(width, height);
//初始化起点,为屏幕外的一个周期
startPoint = new Point(-cycle * 4, 0);
}
/** * 测量宽高 * *@param defaultSize *@param measureSpec *@return */
private int measureSize(int defaultSize, int measureSpec) {
int result = defaultSize;
int mode = MeasureSpec.getMode(measureSpec);
int size = MeasureSpec.getSize(measureSpec);
switch (mode) {
case MeasureSpec.UNSPECIFIED:
result = defaultSize;
break;
case MeasureSpec.AT_MOST:
case MeasureSpec.EXACTLY:
result = size;
break;
}
return result;
}
绘制图形
重写onDraw()来绘制我们的图形,我们看一下onDraw()执行顺序
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//设置内间距
setPadding(20, 20, 20, 20);
//裁剪画布为圆形
clipCicle(canvas);
//绘制圆形边框
drawCicleBorder(canvas);
//绘制波浪区域
drawWavePath(canvas);
//绘制进度文字
drawProcessText(canvas);
//自动增长进度
if (isAutoIncrease) {
if (progress >= 100) {
progress = 0;
} else {
progress++;
}
}
//更新UI
postInvalidateDelayed(waveSpeech);
}
1、裁剪画布为圆形
/** * 裁剪画布为圆形 * *@param canvas */
private void clipCicle(Canvas canvas) {
Path circlePath = new Path();
circlePath.addCircle(width / 2, height / 2, width / 2, Path.Direction.CW);
canvas.clipPath(circlePath);
}
2、绘制圆形边框
/** * 绘制圆形边框 * *@param canvas */
private void drawCicleBorder(Canvas canvas) {
canvas.drawPaint(circlePaint);
canvas.drawCircle(width / 2, height / 2, width / 2, circlePaint);
}
3、绘制波浪区域
/** * 绘制波浪区域 * *@param canvas */
private void drawWavePath(Canvas canvas) {
//根据进度改变起点坐标的y值
startPoint.y = (int) ((1 - (progress / 100.0)) * (height / 2 + width / 2));
Log.e("TAG", "startPoint.y:" + startPoint.y);
//移动区域起点
path.moveTo(startPoint.x, startPoint.y);
int j = 1;
//循环绘制正弦曲线区域,循环两个周期
for (int i = 1; i <= 8; i++) {
if (i % 2 == 0) {
//波峰
path.quadTo(startPoint.x + (cycle * j), startPoint.y + waveHeight,
startPoint.x + (cycle * 2) * i, startPoint.y);
} else {
//波谷
path.quadTo(startPoint.x + (cycle * j), startPoint.y - waveHeight,
startPoint.x + (cycle * 2) * i, startPoint.y);
}
j += 2;
}
//绘制封闭的区域
path.lineTo(width, height);//右下角
path.lineTo(startPoint.x, height);//左下角
path.lineTo(startPoint.x, startPoint.y);//起点
path.close();
//绘制区域
canvas.drawPath(path, wavePaint);
path.reset();
//一开始的起点是在-160,160 = 40 + 40 + 40 + 40,走完一个周期则回到原点
if (startPoint.x + translateX >= 0) {
startPoint.x = -cycle * 4;
} else {
startPoint.x += translateX;
}
}
4、绘制进度文字
/** * 绘制进度文字 * *@param canvas */
private void drawProcessText(Canvas canvas) {
//画布的大小
Rect targetRect = new Rect(0, 0, width, height);
Paint.FontMetricsInt fontMetrics = textPaint.getFontMetricsInt();
int baseline = (targetRect.bottom + targetRect.top - fontMetrics.bottom - fontMetrics.top) / 2;
// 下面这行是实现水平居中,drawText对应改为传入targetRect.centerX()
textPaint.setTextAlign(Paint.Align.CENTER);
canvas.drawText(progress + "%", targetRect.centerX(), baseline, textPaint);
}
提供其他API
/** * 开启自动增长 */
public void startIncrease() {
isAutoIncrease = true;
invalidate();
}
/** * 设置当前进度 * *@param progress 进度 */
public void setProgress(int progress) {
if (progress > 100 || progress < 0)
throw new RuntimeException(getClass().getName() + "请设置[0,100]之间的值");
this.progress = progress;
invalidate();
}
/** * 通过动画设置当前进度 * *@param targetProcess 进度 <=100 *@param duration 动画时长 */
public void setProgress(final int targetProcess, int duration) {
if (progress > 100 || progress < 0)
throw new RuntimeException(getClass().getName() + "请设置[0,100]之间的值");
ValueAnimator progressAnimator = ValueAnimator.ofInt(progress, targetProcess);
progressAnimator.setDuration(duration);
progressAnimator.setTarget(progress);
progressAnimator.setInterpolator(new LinearInterpolator());
progressAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
setProgress((Integer) animation.getAnimatedValue());
}
});
progressAnimator.start();
}
/** * 获取当前进度 * *@return */
public int getProgress() {
return progress;
}
API使用
public class WaterWaveActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_water_wave);
// API三选一即可
// 设置当前进度条
((WaveView) findViewById(R.id.wv)).setProgress(50);
// 在10秒钟内将进度条增长到50%
((WaveView) findViewById(R.id.wv)).setProgress(50, 10000);
// 自动增长进度从0到100
((WaveView) findViewById(R.id.wv)).startIncrease();
}
}
更多推荐
所有评论(0)