在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; } }
实现效果