在Android的一些app中,常常有一些水波紋的加載效果,很是好看,好比下面的爲知筆記的加載效果就是很是的好看~~android
還有一些加速球等等中的波浪效果也是相似。那麼應該怎麼實現這種效果呢?咱們從效果上看,這個效果大概能夠分爲兩個難點。canvas
繪製波浪圖形app
讓波浪隨時間盪漾起來ide
1.分析this
先說第一個,如何繪製波浪圖形。繪製波浪圖形的方法有不少,這裏介紹一種最簡單的方法,就是使用canvas的drawLine方法繪製直線。咱們能夠將view的寬度轉化成弧度,經過sin或者cos方法獲取每一個像素點的座標,經過drawline繪製一條從頂點到底部的直線,這樣均可以達到效果。spa
再說第二個,這個是一個難點,可是實現起來卻很簡單。咱們獲取的座標是從0-360度的座標,也就是說,最後一個的座標接下來的座標應該是第一的座標,它們是一個連續的沒有斷開的座標系列,那麼咱們只須要將座標按照必定的規則交換一下位置就能夠實現波浪的盪漾效果了。code
2.關鍵代碼get
計算波浪上全部點的座標能夠使用以下公式:y = A×sin(x × Φ + offset) + H,A表明了波浪的振幅,x表明了當前view的寬度的位置,Φ表明了2 Math.PI / width,H表明了Y軸上的基本高度。it
//計算Y軸的座標 private float getYPosition(int x, int swing, int offset, int baseHeight) { float cycle = (float) (2 * Math.PI) / mWidth; return (float) Math.sin(cycle * x + offset) * swing + baseHeight; }
偏移座標的方法也很簡單,根據響應的步長設置每次的偏移起始點io
private void changeRestorePosition() { if (mWidth != 0) { mPosition1 = (mPosition1 + STEP1) % mWidth; System.arraycopy(mContentOneYs, mPosition1, mRestoreOnes, 0, mWidth - mPosition1); System.arraycopy(mContentOneYs, 0, mRestoreOnes, mWidth - mPosition1, mPosition1); mPosition2 = (mPosition2 + STEP2) % mWidth; System.arraycopy(mContentTwoys, mPosition2, mRestoreTwos, 0, mWidth - mPosition2); System.arraycopy(mContentTwoys, 0, mRestoreTwos, mWidth - mPosition2, mPosition2); } }
完整代碼
package com.app.motion.wavemotion.view; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.util.AttributeSet; import android.view.View; /** * Created by joe.wang on 2016/10/27. */ public class WaveView extends View { private final int INIT_BASE_HEIGHT1 = 300; private final int INIT_BASE_HEIGHT2 = 300; private int mHeight; private int mWidth; private float[] mContentOneYs = null; private float[] mContentTwoys = null; private float[] mRestoreOnes = null; private float[] mRestoreTwos = null; private static final int SWINGONE = 40; private static final int SWINGTWO = 80; private static final int OFFSETONE = 0; private static final int OFFSETTWO = 40; private int mPosition1 = 0; private int mPosition2 = 0; private static final int STEP1 = 5; private static final int STEP2 = 8; private Paint mPaint1; private Paint mPaint2; public WaveView(Context context) { this(context, null); } public WaveView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public WaveView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { mPaint1 = new Paint(Paint.ANTI_ALIAS_FLAG); mPaint1.setColor(Color.parseColor("#AB9DCF")); mPaint1.setStrokeWidth(4); mPaint1.setAlpha(155); mPaint2 = new Paint(Paint.ANTI_ALIAS_FLAG); mPaint2.setColor(Color.parseColor("#A2D1F3")); mPaint2.setStrokeWidth(4); mPaint2.setAlpha(155); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); if (w != 0 || h != 0 || w != oldw || h != oldh) { mWidth = w; mHeight = h; calculatePoints(); } } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.save(); changeRestorePosition(); for (int i = 0; i < mWidth; i++) { final int x = i; final float y1 = mRestoreOnes[i]; final float y2 = mRestoreTwos[i]; canvas.drawLine(x, y2, x, mHeight, mPaint2); canvas.drawLine(x, y1, x, mHeight, mPaint1); } invalidate(); } private void calculatePoints() { mContentOneYs = new float[mWidth]; mContentTwoys = new float[mWidth]; mRestoreOnes = new float[mWidth]; mRestoreTwos = new float[mWidth]; for (int i = 0; i < mWidth; i++) { mContentOneYs[i] = getYPosition(i, SWINGONE, OFFSETONE, INIT_BASE_HEIGHT1); mContentTwoys[i] = getYPosition(i, SWINGTWO, OFFSETTWO, INIT_BASE_HEIGHT2); } } private void changeRestorePosition() { if (mWidth != 0) { mPosition1 = (mPosition1 + STEP1) % mWidth; System.arraycopy(mContentOneYs, mPosition1, mRestoreOnes, 0, mWidth - mPosition1); System.arraycopy(mContentOneYs, 0, mRestoreOnes, mWidth - mPosition1, mPosition1); mPosition2 = (mPosition2 + STEP2) % mWidth; System.arraycopy(mContentTwoys, mPosition2, mRestoreTwos, 0, mWidth - mPosition2); System.arraycopy(mContentTwoys, 0, mRestoreTwos, mWidth - mPosition2, mPosition2); } } private float getYPosition(int x, int swing, int offset, int baseHeight) { float cycle = (float) (2 * Math.PI) / mWidth; return (float) Math.sin(cycle * x + offset) * swing + baseHeight; } }
實現效果