贝塞尔曲线绘制波浪
程序员文章站
2023-12-27 09:10:09
...
效果图:
关于贝塞尔曲线的介绍可以参照文章
https://www.cnblogs.com/wjtaigwh/p/6647114.html
了解完贝塞尔曲线就来完成波浪自定义View
大体思路就是先绘制一条超出屏幕长的二阶贝塞尔曲线,然后再动画循环平移曲线。
package com.xingyun.waveapplication;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.LinearInterpolator;
/**
* Created by SY on 2018/5/1.
*/
public class WaveView1 extends View {
private int width = 0;
private int height = 0;
private int baseHeight = 0;// 波浪高度
private int waveHeight = 200;// 波峰波、波谷高度
private int waveWidth;//波浪宽度
private float offset = 0;//偏移量
private Paint paint;
public WaveView1(Context context, AttributeSet attrs) {
super(context, attrs);
initPaint();
}
/**
* 设置开启动画
*/
private void startAni() {
ValueAnimator animator = ValueAnimator.ofFloat(0, waveWidth);
animator.setInterpolator(new LinearInterpolator());
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float animatorValue = (float) animation.getAnimatedValue();
offset = animatorValue;
postInvalidate();
}
});
animator.setDuration(1000);
animator.setRepeatCount(ValueAnimator.INFINITE);
animator.start();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawPath(getPath(), paint);
}
//初始化paint
private void initPaint() {
paint = new Paint();
paint.setColor(Color.parseColor("#88FFFFFF"));
paint.setStyle(Paint.Style.FILL);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
width = getMeasuredWidth();
height = getMeasuredHeight();
waveWidth = width;
baseHeight = height / 2;
startAni();
}
/**
* 生成path
*
* @return
*/
private Path getPath() {
int itemWidth = waveWidth / 2;//波长
Path path = new Path();
path.moveTo(-itemWidth * 3 , baseHeight);//起始点坐标
for (int count = -3; count < 2; count++) {
int controlX = count * itemWidth;
path.quadTo(controlX + itemWidth / 2 + offset,//控制点的X
getWaveHeight(count),//控制点的Y
controlX + itemWidth + offset,//结束点的X
baseHeight//结束点的Y
);
}
//封闭区域
path.lineTo(width, height);
path.lineTo(0, height);
path.close();
return path;
}
//计算波峰、波谷
private int getWaveHeight(int num) {
if (num % 2 == 0) {
return baseHeight - waveHeight;
}
return baseHeight + waveHeight;
}
}
初始化画笔之后再onLayout方法获取宽高,然后ondraw方法里绘制关键的曲线。通过getPath方法得到曲线的path。通过path.moveTo方法设置起始点坐标,调用path.quadTo绘制曲线,quadTo四个参数分别为控制点的XY坐标和结束点的XY坐标。完成后调用path.lineTo连接屏幕底部,将区域封闭起来。其中控制点Y坐标为一上一下交替,通过 getWaveHeight方法判断是波峰还是波谷。这样波浪曲线就绘制完成了。最后只要设置动画不断重绘并且循环动画就完成了。