一·效果图:
根据 y = A*sin(wx + b) + h;来画出我们的波纹
基本思路:
1.将view的一个宽度作为一个周期,或者一个周期的整数倍,这样便于计算和编程。
2.用数组保存每一个x值对应的y值,这里的x其实就是横向的像素值,都为整数。
3.然后通过这些数组画线,是纵向划线,然后就行
4.让两条波的速度有一个差值,已形成层次感
package com.liaoli.xfermode.view; import android.content.Context; import android.graphics.Canvas; import android.graphics.DrawFilter; import android.graphics.Paint; import android.graphics.PaintFlagsDrawFilter; import android.util.AttributeSet; import android.view.View; /** * Created by liaoli on 2016/3/5. */ public class DynamicWaveView extends View { /** * 一个正常周期的y值 */ private float[] mYPositions; /** * 第一条波纹的y值 */ private float[] mlineOneYPositions; /** * 第二条波纹的y值 */ private float[] mLineTwoYPositions; /** * 第一条波纹移动的速度 */ private int DEFUALT_TRANSLATE_X_SPEED_ONE = 70; /** * *第二条波纹移动的速度 */ private int DEFUALT_TRANSLATE_X_SPEED_two = 50; /** * 转换成像素的速度 */ private int mXOffSpeedOne, mXOffSpeedTwo; /** * 移动的距离 */ private int mXOneOffset, mXTwoOffset; private Paint mPaint; private DrawFilter mDrawFilter; private int waveColor = 0x880000aa; private int STRETCH_FACTOR_A = 20; private int OFFSET_Y = 100; private float mCycleFactorW; private int mTotalW; private int mTotalH; public DynamicWaveView(Context context) { this(context, null); } public DynamicWaveView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public DynamicWaveView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); /** * 转换成像素是的在不同的手机上面的移动速度都是一样的 */ mXOffSpeedOne = UiUtils.dipToPx(context,DEFUALT_TRANSLATE_X_SPEED_ONE); mXOffSpeedTwo = UiUtils.dipToPx(context,DEFUALT_TRANSLATE_X_SPEED_two); mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPaint.setStyle(Paint.Style.FILL); mPaint.setColor(waveColor); mDrawFilter = new PaintFlagsDrawFilter(0,Paint.ANTI_ALIAS_FLAG|Paint.FILTER_BITMAP_FLAG); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.setDrawFilter(mDrawFilter); resetPositionY(); /** * 画两条波纹。是通过划线的方式来实现的 * 之所以要画线,是要实现装满水的效果 */ for(int i = 0 ; i < mTotalW; i++){ canvas.drawLine(i,mlineOneYPositions[i],i,mTotalH,mPaint); canvas.drawLine(i,mLineTwoYPositions[i],i,mTotalH,mPaint); } /** * 两条波纹的移动距离 */ mXOneOffset += mXOffSpeedOne; mXTwoOffset += mXOffSpeedTwo; /** * 如果移动距离,超过view的宽度时,相当于进入下一个周期,回复初始值 */ if (mXOneOffset > mTotalW) { mXOneOffset = 0; } /** * 如果移动距离,超过view的宽度时,相当于进入下一个周期,回复初始值 */ if (mXTwoOffset > mTotalW) { mXTwoOffset = 0; } /** * 重新绘制 */ postInvalidate(); } /** * 根据波移动的距离,来改变波的对应点的值,这里是纯数学知识 *看不明白的画一下图,马上就明白了 */ private void resetPositionY() { int lineOneInterval = mYPositions.length - mXOneOffset; System.arraycopy(mYPositions,mXOneOffset,mlineOneYPositions,0,lineOneInterval); System.arraycopy(mYPositions,0,mlineOneYPositions,lineOneInterval,mXOneOffset); int lineTwoInterval = mYPositions.length - mXTwoOffset; System.arraycopy(mYPositions,mXTwoOffset,mLineTwoYPositions,0,lineTwoInterval); System.arraycopy(mYPositions,0,mLineTwoYPositions,lineTwoInterval,mXTwoOffset); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); } /** * 此方法调用在onMeasure之后,onDraw之前。 * @param w * @param h * @param oldw * @param oldh */ @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); mTotalW = w; mTotalH = h; mYPositions = new float[w]; mlineOneYPositions = new float[w]; mLineTwoYPositions = new float[w]; /** * 周期 */ mCycleFactorW = (float) (2*Math.PI /w); /** * 通过正玄函数来算一个周期的Y值,并保存在一个数组中 */ for(int i = 0 ; i < w; i++){ mYPositions[i] = (float) (STRETCH_FACTOR_A * Math.sin(mCycleFactorW *i) + OFFSET_Y); } } }