前几天撸了个贝塞尔曲线,最近看到波浪图很敢兴趣,想着也是贝塞尔曲线。真实做的时候使用的不是贝塞尔但是也是数学公式。其实贝塞尔曲线一样能做出来。
注意看那个浅红色部分。特意使用颜色不一样的
WaveView,主要靠做bitmap然后通过正弦直接看代码
public class WaveView extends View { //*************属性开始**************// /** * 振幅比例 */ private static final float DEFAULT_AMPLITUDE_RATIO = 0.05f; /** * 水位比例 */ private static final float DEFAULT_WATER_LEVEL_RATIO = 0.5f; /** * 波长比例 */ private static final float DEFAULT_WAVE_LENGTH_RATIO = 1.0f; /** * 偏移 */ private static final float DEFAULT_WAVE_SHIFT_RATIO = 0.0f; /** * 后面波浪的颜色 */ public static final int DEFAULT_BEHIND_WAVE_COLOR = Color.parseColor("#28FFFFFF"); /** * 前面波浪的颜色 */ public static final int DEFAULT_FRONT_WAVE_COLOR = Color.parseColor("#3CFFFFFF"); /** * 外观样式 */ public static final ShapeType DEFAULT_WAVE_SHAPE = ShapeType.CIRCLE; public enum ShapeType { CIRCLE, SQUARE } /** * 是否展示波浪动画 */ private boolean mShowWave; /** * 着色器 */ private BitmapShader mWaveShader; /** * shader矩阵 */ private Matrix mShaderMatrix; /** * view的画笔 */ private Paint mViewPaint; /** * 边界border的画笔 */ private Paint mBorderPaint; /** * 默认振幅 */ private float mDefaultAmplitude; /** * 默认水位 */ private float mDefaultWaterLevel; /** * 默认wave宽度 */ private float mDefaultWaveLength; /** * 默认波浪角频率 */ private double mDefaultAngularFrequency; /** * 默认振幅比例 */ private float mAmplitudeRatio = DEFAULT_AMPLITUDE_RATIO; /** * 波浪宽度 */ private float mWaveLengthRatio = DEFAULT_WAVE_LENGTH_RATIO; /** * 波浪水位 */ private float mWaterLevelRatio = DEFAULT_WATER_LEVEL_RATIO; /** * 位移 */ private float mWaveShiftRatio = DEFAULT_WAVE_SHIFT_RATIO; /** * 默认后面波浪颜色 */ private int mBehindWaveColor = DEFAULT_BEHIND_WAVE_COLOR; /** * 默认前面波浪颜色 */ private int mFrontWaveColor = DEFAULT_FRONT_WAVE_COLOR; /** * 默认着色外观 */ private ShapeType mShapeType = DEFAULT_WAVE_SHAPE; //*************属性结束**************// public WaveView(Context context) { super(context); init(); } public WaveView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public WaveView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } /** * 做一些初始化的操作 */ private void init() { mShaderMatrix = new Matrix(); mViewPaint = new Paint(); mViewPaint.setAntiAlias(true); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); createShader(); } /** * 绘制初始波形 */ private void createShader() { mDefaultAngularFrequency = 2.0f * Math.PI / DEFAULT_WAVE_LENGTH_RATIO / getWidth(); //默认振幅()= 控件的高度* 默认振幅比例 mDefaultAmplitude = getHeight() * DEFAULT_AMPLITUDE_RATIO; mDefaultWaterLevel = getHeight() * DEFAULT_WATER_LEVEL_RATIO; mDefaultWaveLength = getWidth(); //创建长宽恰等于WaveView的Bitmap Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); Paint wavePaint = new Paint(); wavePaint.setStrokeWidth(2); wavePaint.setAntiAlias(true); //把波浪画到bitmap上面 //画一个正弦曲线 // y=Asin(ωx+φ)+h final int endX = getWidth() + 1; final int endY = getHeight() + 1; float[] waveY = new float[endX]; //初始化后面波浪 wavePaint.setColor(mBehindWaveColor); for (int beginX = 0; beginX < endX; beginX++) { //波浪形的x double wx = beginX * mDefaultAngularFrequency; //开始y的值通过公式计算 float beginY = (float) (mDefaultWaterLevel + mDefaultAmplitude * Math.sin(wx)); canvas.drawLine(beginX, beginY, beginX, endY, wavePaint); waveY[beginX] = beginY; } //初始化前面波浪 前面波浪相对于后面波浪的偏移量 wavePaint.setColor(mFrontWaveColor); final int wave2Shift = (int) (mDefaultWaveLength / 4); for (int beginX = 0; beginX < endX; beginX++) { canvas.drawLine(beginX, waveY[(beginX + wave2Shift) % endX], beginX, endY, wavePaint); } //产生一个画有一个位图的渲染器 , // Shader.TileMode.REPEAT: 在x轴上面的平铺模式、REPEAT:横向和纵向的重复渲染器图片,平铺 //Shader.TileMode.CLAMP 渲染器超出原始边界范围,会复制范围内边缘染色 // 在x轴采用横向和纵向平铺。在y轴采用渲染器超出原始边界范围,会复制范围内边缘染色 mWaveShader = new BitmapShader(bitmap, Shader.TileMode.REPEAT, Shader.TileMode.CLAMP); mViewPaint.setShader(mWaveShader); } @Override protected void onDraw(Canvas canvas) { //如果当前未显示wave if (mShowWave && mWaveShader != null) { //还必须确定自定义控件的shader 不能为空 if (mViewPaint.getShader() == null) { mViewPaint.setShader(mWaveShader); } //先做缩放变换 mShaderMatrix.setScale( mWaveLengthRatio / DEFAULT_WAVE_LENGTH_RATIO,//x轴的缩放比例 mAmplitudeRatio / DEFAULT_AMPLITUDE_RATIO,//y轴的缩放该比例 0,//中心点x mDefaultWaterLevel);//中心点y //再做平移,这里注意下,是postTranslate ,不是setTranslate.是因为需要后乘 mShaderMatrix.postTranslate(mWaveShiftRatio * getWidth(),//在x轴移动的量 (DEFAULT_WATER_LEVEL_RATIO - mWaterLevelRatio) * getHeight()); //在y轴移动的量, //y轴上使用正数进行平移将向下移动图像,而使用负数将向上移动图像。 mWaveShader.setLocalMatrix(mShaderMatrix); //自定义控件的边框宽度 float borderWidth = mBorderPaint == null ? 0f : mBorderPaint.getStrokeWidth(); switch (mShapeType) { case CIRCLE: if (borderWidth > 0) { //如果边框的宽度大于0,则绘制出一个挨着自定义控件的圆形。 //该圆的中心肯定在自定义控件的中心。 canvas.drawCircle(getWidth() / 2f, getHeight() / 2f, (getWidth() - borderWidth) / 2f - 1f, mBorderPaint); } //绘制自定义控件 float radius = getWidth() / 2f - borderWidth; //波形图已经在mViewPaint 中的shader中了 canvas.drawCircle(getWidth() / 2f, getHeight() / 2f, radius, mViewPaint); break; case SQUARE: if (borderWidth > 0) { canvas.drawRect( borderWidth / 2f, borderWidth / 2f, getWidth() - borderWidth / 2f - 0.5f, getHeight() - borderWidth / 2f - 0.5f, mBorderPaint); } canvas.drawRect(borderWidth, borderWidth, getWidth() - borderWidth, getHeight() - borderWidth, mViewPaint); break; } } else { mViewPaint.setShader(null); } } //*********************get和set开始********************************// /** * 得到偏移比例 * * @return 获得偏移的比例 */ public float getWaveShiftRatio() { return mWaveShiftRatio; } /** * 设置波浪转换偏移比例 * * @param waveShiftRatio waveShiftRatio 必须是 0 ~ 1.0的值,默认是0 */ public void setWaveShiftRatio(float waveShiftRatio) { if (mWaveShiftRatio != waveShiftRatio) { mWaveShiftRatio = waveShiftRatio; invalidate(); } } /** * 得到 水位比例 * * @return */ public float getWaterLevelRatio() { return mWaterLevelRatio; } /** * 设置水位比例 * * @param waterLevelRatio 必须是 0 ~ 1. 默认0.5f */ public void setWaterLevelRatio(float waterLevelRatio) { if (mWaterLevelRatio != waterLevelRatio) { mWaterLevelRatio = waterLevelRatio; invalidate(); } } /** * 得到振幅比例 * * @return */ public float getAmplitudeRatio() { return mAmplitudeRatio; }
/**
* 设置振幅比例
*
* @param amplitudeRatio 默认是 0.05. 不能大于1
*/
public void setAmplitudeRatio(float amplitudeRatio) {
if (mAmplitudeRatio != amplitudeRatio) {
mAmplitudeRatio = amplitudeRatio;
invalidate();
}
}
/**
* 得到宽度
*
* @return
*/
public float getWaveLengthRatio() {
return mWaveLengthRatio;
}
/**
* 设置横向波浪宽度的比例
*
* @param waveLengthRatio 默认1
*/
public void setWaveLengthRatio(float waveLengthRatio) {
mWaveLengthRatio = waveLengthRatio;
}
public boolean isShowWave() {
return mShowWave;
}
public void setShowWave(boolean showWave) {
mShowWave = showWave;
}
/**
* 设置 边框的宽度和颜色
*
* @param width
* @param color
*/
public void setBorder(int width, int color) {
if (mBorderPaint == null) {
mBorderPaint = new Paint();
mBorderPaint.setAntiAlias(true);
mBorderPaint.setStyle(Paint.Style.STROKE);
}
mBorderPaint.setColor(color);
mBorderPaint.setStrokeWidth(width);
invalidate();
}
/**
* 设置 波浪的颜色
*
* @param behindWaveColor 后面波浪的颜色
* @param frontWaveColor 前面波浪的颜色
*/
public void setWaveColor(int behindWaveColor, int frontWaveColor) {
mBehindWaveColor = behindWaveColor;
mFrontWaveColor = frontWaveColor;
if (getWidth() > 0 && getHeight() > 0) {
// need to recreate shader when color changed
mWaveShader = null;
createShader();
invalidate();
}
}
/**
* 设置外形
*
* @param shapeType
*/
public void setShapeType(ShapeType shapeType) {
mShapeType = shapeType;
invalidate();
}
//*********************get和set结束********************************//
}
WaveAnimatorHelper类,这个还有问题。太晚了。。睡觉去
public class WaveAnimatorHelper { /** * 动画集合 */ private static AnimatorSet mAnimatorSet; private static List<Animator> animators; /** * 偏移量动画 */ private static ObjectAnimator waveShiftAnim; /** * 水位高度动画 */ private static ObjectAnimator waterLevelAnim; /** * 振幅角度动画 */ private static ObjectAnimator amplitudeAnim; private static ObjectAnimator objectAnimator; /** * 是否暂停 */ private static boolean isPause = false; public enum ANIMATORTYPE { PROPERTYVALUES, ANIMATORSET }
/**
* 工具类的构造方法通常私有化
*/
private WaveAnimatorHelper(ANIMATORTYPE type, float waterLevelStart, float waterLevelEnd, float waveShiftStart,
float waveShiftEnd, float amplitudeStart, float amplitudeEnd, WaveView mWaveView, int duration) {
//改变偏移量
if (type == ANIMATORTYPE.PROPERTYVALUES) {
// PropertyValuesHolder waterLevelAnim = PropertyValuesHolder.ofFloat("waterLevelRatio", 0.0f, 0.5f);
PropertyValuesHolder waterLevelAnim = PropertyValuesHolder.ofFloat("waterLevelRatio", waterLevelStart, waterLevelEnd);
// PropertyValuesHolder waveShiftAnim = PropertyValuesHolder.ofFloat("waveShiftRatio", 0f, 1f);
PropertyValuesHolder waveShiftAnim = PropertyValuesHolder.ofFloat("waveShiftRatio", waveShiftStart, waveShiftEnd);
// PropertyValuesHolder amplitudeAnim = PropertyValuesHolder.ofFloat("amplitudeRatio", 0.0001f, 0.08f);
PropertyValuesHolder amplitudeAnim = PropertyValuesHolder.ofFloat("amplitudeRatio", amplitudeStart, amplitudeEnd);
objectAnimator = ObjectAnimator.ofPropertyValuesHolder(mWaveView, waterLevelAnim, waveShiftAnim, amplitudeAnim);
objectAnimator.setDuration(duration);
objectAnimator.setRepeatMode(REVERSE);
objectAnimator.setRepeatCount(INFINITE);
objectAnimator.start();
} else {
animators = new ArrayList<>();
waveShiftAnim = ObjectAnimator.ofFloat(
mWaveView, "waveShiftRatio", waveShiftStart, waveShiftEnd);
// 无限 循环
waveShiftAnim.setRepeatCount(ValueAnimator.INFINITE);
waveShiftAnim.setDuration(duration);
//匀速线性差值器
waveShiftAnim.setInterpolator(new LinearInterpolator());
animators.add(waveShiftAnim);
// 改变水位比例
waterLevelAnim = ObjectAnimator.ofFloat(
mWaveView, "waterLevelRatio", waterLevelStart, waterLevelEnd);
waterLevelAnim.setDuration(duration * 3);
waterLevelAnim.setRepeatCount(ValueAnimator.INFINITE);
waterLevelAnim.setRepeatMode(ValueAnimator.REVERSE);
//减速差值器
waterLevelAnim.setInterpolator(new DecelerateInterpolator());
animators.add(waterLevelAnim);
// 改变振幅比例
amplitudeAnim = ObjectAnimator.ofFloat(
mWaveView, "amplitudeRatio", amplitudeStart, amplitudeEnd);
amplitudeAnim.setRepeatCount(ValueAnimator.INFINITE);
amplitudeAnim.setRepeatMode(ValueAnimator.REVERSE);
amplitudeAnim.setDuration(duration * 2);
amplitudeAnim.setInterpolator(new LinearInterpolator());
animators.add(amplitudeAnim);
mAnimatorSet = new AnimatorSet();
mAnimatorSet.playTogether(animators);
if (mAnimatorSet != null) {
mAnimatorSet.start();
}
}
}
/**
* 通过ObjectAnimator.ofPropertyValuesHolder方式启动动画。3个动画持续时间相同
*
* @param waterLevelStart 水位开始位置
* @param waterLevelEnd 水位结束位置
* @param waveShiftStart 偏移开始位置
* @param waveShiftEnd 偏移结束位置
* @param amplitudeStart 振幅开始
* @param amplitudeEnd 振幅结束
* @param waveView 当前waveview
* @param duration 持续时间
* @return
*/
public static WaveAnimatorHelper startAnimatorWithPropertyValuesHolder
(float waterLevelStart, float waterLevelEnd, float waveShiftStart,
float waveShiftEnd, float amplitudeStart, float amplitudeEnd, WaveView waveView, int duration) {
return new WaveAnimatorHelper(ANIMATORTYPE.PROPERTYVALUES, waterLevelStart, waterLevelEnd, waveShiftStart,
waveShiftEnd, amplitudeStart, amplitudeEnd, waveView, duration);
}
/**
* 通过ObjectAnimator.ofPropertyValuesHolder方式启动动画。3个动画持续时间相同
*
* @param waterLevelStart 水位开始位置
* @param waterLevelEnd 水位结束位置
* @param waveShiftStart 偏移开始位置
* @param waveShiftEnd 偏移结束位置
* @param amplitudeStart 振幅开始
* @param amplitudeEnd 振幅结束
* @param waveView 当前waveview
* @param duration 持续时间
* @return
*/
public static WaveAnimatorHelper startAnimatorWithAnimatorSet
(float waterLevelStart, float waterLevelEnd, float waveShiftStart,
float waveShiftEnd, float amplitudeStart, float amplitudeEnd, WaveView waveView, int duration) {
return new WaveAnimatorHelper(ANIMATORTYPE.ANIMATORSET, waterLevelStart, waterLevelEnd, waveShiftStart,
waveShiftEnd, amplitudeStart, amplitudeEnd, waveView, duration);
}
/**
* 暂停PropertyValuesHolder动画
*/
@TargetApi(Build.VERSION_CODES.KITKAT)
public static void stopAnimatorWithPropertyValuesHolder() {
if (objectAnimator != null) {
if (!isPause) {
objectAnimator.pause();
isPause = true;
}
}
}
/**
* 继续PropertyValuesHolder动画
*/
@TargetApi(Build.VERSION_CODES.KITKAT)
public static void resumePropertyValuesHolder() {
if (objectAnimator != null) {
if (isPause) {
objectAnimator.resume();
isPause = false;
return;
}
objectAnimator.resume();
}
}
public static void stopAnimationWithAnimatorSet(){
if(mAnimatorSet != null){
}
}
}
在activity中多了几行代码
waveView = (WaveView) findViewById(R.id.wave1); waveView.setShowWave(true); waveView.setWaveColor( Color.parseColor("#28f16d7a"), Color.parseColor("#3cf16d7a")); waveView.setShapeType(WaveView.ShapeType.SQUARE); WaveAnimatorHelper.startAnimatorWithAnimatorSet(0.0f, 0.4f, 0f, 1f, 0.0001f, 0.2f, waveView, 1000);