贝塞尔曲线学习【1】
今天学习了贝塞尔曲线的相关内容
特别感谢 http://blog.csdn.net/z82367825/article/details/51599245 博文。
具体的理论知识就不写了。
在此处记录下 修改过的 波浪图(由原来的一条增加为3条交替变化)。如下图所示。具体实现可以参考上面的文章。
这里是绘制了三条贝塞尔曲线组合而成的效果。代码如下:
package com.zero.bezier.widget.wave;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.graphics.Shader;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.LinearInterpolator;
public class WaveView extends View {
/**
* 波峰
*/
private float mWavePeak = 35f;
/**
* 波槽
*/
private float mWaveTrough = 35f;
/**
* 水位
*/
private float mWaveHeight = 350f;
private Paint mPaintWave1;
private Path mPathWave1;
private int mWaterColorWave1 = 0x990000FF;
private Paint mPaintWave2;
private Path mPathWave2;
private int mWaterColorWave2 = 0x550000FF;
private Paint mPaintWave3;
private Path mPathWave3;
private int mWaterColorWave3 = 0x220000FF;
public WaveView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public WaveView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public WaveView(Context context) {
super(context);
init();
}
private void init() {
mPathWave1 = new Path();
mPaintWave1 = new Paint();
mPaintWave1.setAntiAlias(true);
//mPaintWave1.setStyle(Paint.Style.FILL);
//mPaintWave1.setColor(mWaterColorWave1);
//mPaintWave1.setColor(getResources().getColor(android.R.color.holo_blue_bright));
mPathWave2 = new Path();
mPaintWave2 = new Paint();
mPaintWave2.setAntiAlias(true);
mPaintWave2.setStyle(Paint.Style.FILL);
mPaintWave2.setColor(mWaterColorWave2);
//mPaintWave2.setColor(getResources().getColor(android.R.color.holo_red_light));
mPathWave3 = new Path();
mPaintWave3 = new Paint();
mPaintWave3.setAntiAlias(true);
mPaintWave3.setStyle(Paint.Style.FILL);
mPaintWave3.setColor(mWaterColorWave3);
//mPaintWave3.setColor(getResources().getColor(android.R.color.holo_green_light));
LinearGradient linearGradient = new LinearGradient(
0,
0,
720,
720,
mWaterColorWave1,
mWaterColorWave3,
Shader.TileMode.CLAMP);
mPaintWave1.setShader(linearGradient);
}
private float mWidth, mHeight;
private PointF mWave1Start;
private PointF mWave1Left1, mWave1Left2, mWave1First, mWave1Second, mWave1Right;
private PointF mWave1ControlLeft1, mWave1ControlLeft2, mWave1ControlFirst, mWave1ControlSecond;
private PointF mWave2Start;
private PointF mWave2Left1, mWave2Left2, mWave2First, mWave2Second, mWave2Right;
private PointF mWave2ControlLeft1, mWave2ControlLeft2, mWave2ControlFirst, mWave2ControlSecond;
private PointF mWave3Start;
private PointF mWave3Left1, mWave3Left2, mWave3First, mWave3Second, mWave3Right;
private PointF mWave3ControlLeft1, mWave3ControlLeft2, mWave3ControlFirst, mWave3ControlSecond;
private boolean mIsRunning = false;
private boolean mHasInit = false;
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
if (!mHasInit) {
mWidth = w;
mHeight = h;
mHasInit = true;
}
super.onSizeChanged(w, h, oldw, oldh);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (!mIsRunning || !mHasInit)
return;
mPathWave1.reset();
mPathWave1.moveTo(mWave1Left1.x, mWave1Left1.y);
mPathWave1.quadTo(mWave1ControlLeft1.x, mWave1ControlLeft1.y, mWave1Left2.x, mWave1Left2.y);
mPathWave1.quadTo(mWave1ControlLeft2.x, mWave1ControlLeft2.y, mWave1First.x, mWave1First.y);
mPathWave1.quadTo(mWave1ControlFirst.x, mWave1ControlFirst.y, mWave1Second.x, mWave1Second.y);
mPathWave1.quadTo(mWave1ControlSecond.x, mWave1ControlSecond.y, mWave1Right.x, mWave1Right.y);
mPathWave1.lineTo(mWave1Right.x, mHeight);
mPathWave1.lineTo(mWave1Left1.x, mHeight);
mPathWave1.lineTo(mWave1Left1.x, mWave1Left1.y);
canvas.drawPath(mPathWave1, mPaintWave1);
mPathWave2.reset();
mPathWave2.moveTo(mWave2Left1.x, mWave2Left1.y);
mPathWave2.quadTo(mWave2ControlLeft1.x, mWave2ControlLeft1.y, mWave2Left2.x, mWave2Left2.y);
mPathWave2.quadTo(mWave2ControlLeft2.x, mWave2ControlLeft2.y, mWave2First.x, mWave2First.y);
mPathWave2.quadTo(mWave2ControlFirst.x, mWave2ControlFirst.y, mWave2Second.x, mWave2Second.y);
mPathWave2.quadTo(mWave2ControlSecond.x, mWave2ControlSecond.y, mWave2Right.x, mWave2Right.y);
mPathWave2.lineTo(mWave2Right.x, mHeight);
mPathWave2.lineTo(mWave2Left1.x, mHeight);
mPathWave2.lineTo(mWave2Left1.x, mWave2Left1.y);
canvas.drawPath(mPathWave2, mPaintWave2);
mPathWave3.reset();
mPathWave3.moveTo(mWave3Left1.x, mWave3Left1.y);
mPathWave3.quadTo(mWave3ControlLeft1.x, mWave3ControlLeft1.y, mWave3Left2.x, mWave3Left2.y);
mPathWave3.quadTo(mWave3ControlLeft2.x, mWave3ControlLeft2.y, mWave3First.x, mWave3First.y);
mPathWave3.quadTo(mWave3ControlFirst.x, mWave3ControlFirst.y, mWave3Second.x, mWave3Second.y);
mPathWave3.quadTo(mWave3ControlSecond.x, mWave3ControlSecond.y, mWave3Right.x, mWave3Right.y);
mPathWave3.lineTo(mWave3Right.x, mHeight);
mPathWave3.lineTo(mWave3Left1.x, mHeight);
mPathWave3.lineTo(mWave3Left1.x, mWave3Left1.y);
canvas.drawPath(mPathWave3, mPaintWave3);
}
private void reset() {
mWave1Start = new PointF(-mWidth, mHeight - mWaveHeight);
mWave1Left1 = new PointF(-mWidth, mHeight - mWaveHeight);
mWave1Left2 = new PointF(-mWidth / 2f, mHeight - mWaveHeight);
mWave1First = new PointF(0, mHeight - mWaveHeight);
mWave1Second = new PointF(mWidth / 2f, mHeight - mWaveHeight);
mWave1Right = new PointF(mWidth, mHeight - mWaveHeight);
mWave1ControlLeft1 = new PointF(mWave1Left1.x + mWidth / 4f, mWave1Left1.y + mWavePeak);
mWave1ControlLeft2 = new PointF(mWave1Left2.x + mWidth / 4f, mWave1Left2.y - mWaveTrough);
mWave1ControlFirst = new PointF(mWave1First.x + mWidth / 4f, mWave1First.y + mWavePeak);
mWave1ControlSecond = new PointF(mWave1Second.x + mWidth / 4f, mWave1Second.y - mWaveTrough);
mWave2Start = new PointF(-mWidth, mHeight - mWaveHeight);
mWave2Left1 = new PointF(-mWidth, mHeight - mWaveHeight);
mWave2Left2 = new PointF(-mWidth / 2f, mHeight - mWaveHeight);
mWave2First = new PointF(0, mHeight - mWaveHeight);
mWave2Second = new PointF(mWidth / 2f, mHeight - mWaveHeight);
mWave2Right = new PointF(mWidth, mHeight - mWaveHeight);
mWave2ControlLeft1 = new PointF(mWave2Left1.x + mWidth / 4f, mWave2Left1.y + mWavePeak);
mWave2ControlLeft2 = new PointF(mWave2Left2.x + mWidth / 4f, mWave2Left2.y - mWaveTrough);
mWave2ControlFirst = new PointF(mWave2First.x + mWidth / 4f, mWave2First.y + mWavePeak);
mWave2ControlSecond = new PointF(mWave2Second.x + mWidth / 4f, mWave2Second.y - mWaveTrough);
mWave3Start = new PointF(-mWidth, mHeight - mWaveHeight);
mWave3Left1 = new PointF(-mWidth, mHeight - mWaveHeight);
mWave3Left2 = new PointF(-mWidth / 2f, mHeight - mWaveHeight);
mWave3First = new PointF(0, mHeight - mWaveHeight);
mWave3Second = new PointF(mWidth / 2f, mHeight - mWaveHeight);
mWave3Right = new PointF(mWidth, mHeight - mWaveHeight);
mWave3ControlLeft1 = new PointF(mWave3Left1.x + mWidth / 4f, mWave3Left1.y + mWavePeak);
mWave3ControlLeft2 = new PointF(mWave3Left2.x + mWidth / 4f, mWave3Left2.y - mWaveTrough);
mWave3ControlFirst = new PointF(mWave3First.x + mWidth / 4f, mWave3First.y + mWavePeak);
mWave3ControlSecond = new PointF(mWave3Second.x + mWidth / 4f, mWave3Second.y - mWaveTrough);
}
private class WaveHandler extends Handler {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what == ANIM_START) {
reset();
startAnimWave1();
startAnimWave2();
startAnimWave3();
mIsRunning = true;
}
}
}
private WaveHandler mWaveHandler = new WaveHandler();
private static final int ANIM_START = 1;
public void setRunning() {
new Thread(new Runnable() {
@Override
public void run() {
while (!mHasInit) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
mWaveHandler.sendEmptyMessage(ANIM_START);
}
}).start();
}
private void startAnimWave1() {
ValueAnimator valueAnimator = ValueAnimator.ofFloat(mWave1Start.x, 0);
valueAnimator.setInterpolator(new LinearInterpolator());
valueAnimator.setDuration(3000);
valueAnimator.setRepeatCount(Animation.INFINITE);
//动画效果重复
// valueAnimator.setRepeatMode(Animation.RESTART);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mWave1Left1.x = (float) animation.getAnimatedValue();
mWave1Left2 = new PointF(mWave1Left1.x + mWidth / 2f, mHeight - mWaveHeight);
mWave1First = new PointF(mWave1Left2.x + mWidth / 2f, mHeight - mWaveHeight);
mWave1Second = new PointF(mWave1First.x + mWidth / 2f, mHeight - mWaveHeight);
mWave1Right = new PointF(mWave1Second.x + mWidth / 2f, mHeight - mWaveHeight);
mWave1ControlLeft1 = new PointF(mWave1Left1.x + mWidth / 4f, mWave1Left1.y + mWavePeak);
mWave1ControlLeft2 = new PointF(mWave1Left2.x + mWidth / 4f, mWave1Left2.y - mWaveTrough);
mWave1ControlFirst = new PointF(mWave1First.x + mWidth / 4f, mWave1First.y + mWavePeak);
mWave1ControlSecond = new PointF(mWave1Second.x + mWidth / 4f, mWave1Second.y - mWaveTrough);
invalidate();
}
});
valueAnimator.start();
}
private void startAnimWave2() {
ValueAnimator valueAnimator1 = ValueAnimator.ofFloat(mWave2Start.x, 0);
valueAnimator1.setInterpolator(new LinearInterpolator());
valueAnimator1.setDuration(3000);
valueAnimator1.setRepeatCount(Animation.INFINITE);
valueAnimator1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mWave2Left1.x = (float) animation.getAnimatedValue();
mWave2Left2 = new PointF(mWave2Left1.x + mWidth / 2f, mHeight - mWaveHeight);
mWave2First = new PointF(mWave2Left2.x + mWidth / 2f, mHeight - mWaveHeight);
mWave2Second = new PointF(mWave2First.x + mWidth / 2f, mHeight - mWaveHeight);
mWave2Right = new PointF(mWave2Second.x + mWidth / 2f, mHeight - mWaveHeight);
mWave2ControlLeft1 = new PointF(mWave2Left1.x + mWidth / 4f, mWave2Left1.y + mWavePeak);
mWave2ControlLeft2 = new PointF(mWave2Left2.x + mWidth / 4f, mWave2Left2.y - mWaveTrough);
mWave2ControlFirst = new PointF(mWave2First.x + mWidth / 4f, mWave2First.y + mWavePeak);
mWave2ControlSecond = new PointF(mWave2Second.x + mWidth / 4f, mWave2Second.y - mWaveTrough);
invalidate();
}
});
valueAnimator1.setStartDelay(-1800);
valueAnimator1.start();
}
private void startAnimWave3() {
ValueAnimator valueAnimator1 = ValueAnimator.ofFloat(mWave3Start.x, 0);
valueAnimator1.setInterpolator(new LinearInterpolator());
valueAnimator1.setDuration(3000);
valueAnimator1.setRepeatCount(Animation.INFINITE);
valueAnimator1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mWave3Left1.x = (float) animation.getAnimatedValue();
mWave3Left2 = new PointF(mWave3Left1.x + mWidth / 2f, mHeight - mWaveHeight);
mWave3First = new PointF(mWave3Left2.x + mWidth / 2f, mHeight - mWaveHeight);
mWave3Second = new PointF(mWave3First.x + mWidth / 2f, mHeight - mWaveHeight);
mWave3Right = new PointF(mWave3Second.x + mWidth / 2f, mHeight - mWaveHeight);
mWave3ControlLeft1 = new PointF(mWave3Left1.x + mWidth / 4f, mWave3Left1.y + mWavePeak);
mWave3ControlLeft2 = new PointF(mWave3Left2.x + mWidth / 4f, mWave3Left2.y - mWaveTrough);
mWave3ControlFirst = new PointF(mWave3First.x + mWidth / 4f, mWave3First.y + mWavePeak);
mWave3ControlSecond = new PointF(mWave3Second.x + mWidth / 4f, mWave3Second.y - mWaveTrough);
invalidate();
}
});
valueAnimator1.setStartDelay(-800);
valueAnimator1.start();
}
}
此处只记录下自己探索的内容:
1、由一条曲线扩充为多条,是开了多个ValueAnimator来invalidate()视图。
2、为了制造视差,在另外两条曲线的ValueAnimator实例中设定了.setStartDelay()值,使动画的发生值滞后(如果设定正值)或者提前(如果设定负值)。此处,设定了负值,即相位提前,避免在第一个曲线动画开始后,其他曲线存在滞后显示的情况
3、绘制path时,替代使用solid颜色,而是使用gradient实现渐变色
4、下面要探索下,是否 可以只使用一个ValueAnimator即可实现多个贝塞尔曲线交叠显示