实现波浪效果
先看下效果图
分析下实现的基本步骤
这是正弦函数的曲线图,可以把动态的波纹效果看成循环滚动的正弦函数。
1.先在自定义view上绘制静态的正弦函数,主要的四个坐标是
(0,0) , (π/2,1),(π,0),(π3/2,-1),(2π,0)
我们假定绘制的波浪高度是100
对应在屏幕的坐标转换,分别是
(0, height / 2),(width / 4, height / 2 - 100),( width / 2, height / 2),(width / 4 * 3, height / 2 + 100),( width, height / 2);
在自定义view上调用绘制方法即可
path.moveTo(0, height / 2);
path.quadTo(width / 4, height / 2 - 100, width / 2, height / 2);
path.quadTo(width / 4 * 3, height / 2 + 100, width, height / 2);
path.lineTo(width, height);
path.lineTo(0, height);
path.close();
静态的一帧绘制完毕
2.接下来让波浪滚动起来,
将正弦函数屏幕外的曲线绘制出来,我们可以给所有的x左边规定一个offset,随着时间的增加,offset也在增加,这样整个波浪就可以滚动起来了
关键点坐标
(-width + offset, height / 2),(-(width / 4 * 3) + offset, height / 2 - 100),( -(width / 2) + offset, height / 2),(-(width / 4) + offset, height / 2 + 100),
( 0 + offset, height / 2),
(width / 4 + offset, height / 2 - 100),( width / 2 + offset, height / 2),(width / 4 * 3 + offset, height / 2 + 100),(width + offset, height / 2);
接下来就是在规定时间内让offset发生变换,在ondraw方法里对这些变化的path进行绘制,
可以使用到ValueAnimator,让ValueAnimator.ofInt(0, width);通过回调的offset做出绘制,接下来是实现代码
public class WaveView extends View {
private Paint paint;
private Path path;
private int width, height;
/**
* 对画笔进行一些初始化操作
* @param context
* @param attrs
*/
public WaveView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStyle(Paint.Style.FILL);
paint.setStrokeWidth(10);
paint.setColor(Color.BLUE);
path = new Path();
post(new Runnable() {
@Override
public void run() {
initWave();
}
});
}
/**
* 在onMeasure里测量宽度和高度
* @param widthMeasureSpec
* @param heightMeasureSpec
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
width = getMeasuredWidth();
height = getMeasuredHeight();
}
private void initWave() {
// path.moveTo(0, height / 2);
// path.quadTo(width / 4, height / 2 - 300, width / 2, height / 2);
// path.quadTo(width / 4 * 3, height / 2 + 300, width, height / 2);
//
//
// path.lineTo(width, height);
// path.lineTo(0, height);
// path.close();
invalidate();
initAnimator();
}
/**
* 动画的循环周期是2秒,无限循环
*/
private void initAnimator() {
ValueAnimator valueAnimator = ValueAnimator.ofInt(0, width);
valueAnimator.setDuration(2000);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int animatedValue = (int) animation.getAnimatedValue();
initOut(animatedValue);
invalidate();
}
});
valueAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
valueAnimator.start();
valueAnimator.setTarget(this);
valueAnimator.setRepeatCount(ValueAnimator.INFINITE);
}
/**
* path的quadTo()方法运用的就是贝塞尔曲线
* @param offset
*/
private void initOut(int offset) {
path.reset();
path.moveTo(-width + offset, height / 2);
path.quadTo(-(width / 4 * 3) + offset, height / 2 - 100, -(width / 2) + offset, height / 2);
path.quadTo(-(width / 4) + offset, height / 2 + 100, 0 + offset, height / 2);
path.lineTo(0 + offset, height);
path.lineTo(-width + offset, height);
path.moveTo(0 + offset, height / 2);
path.quadTo(width / 4 + offset, height / 2 - 100, width / 2 + offset, height / 2);
path.quadTo(width / 4 * 3 + offset, height / 2 + 100, width + offset, height / 2);
path.lineTo(width + offset, height);
path.lineTo(0 + offset, height);
path.close();
}
/**
* canvas画布对这些路径进行绘制
* @param canvas
*/
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawPath(path, paint);
}
}
在布局文件中引用该自定义view,就可以实现滚动的波浪效果啦。