进入程序员的行业的时间也不短了,然而还没有发表过一篇文章,一直深表惭愧,本人了一直对android的各种特效深感兴趣,今天就来写写水波纹的特效,
通过继承View来自定义水波纹view,实现原理:通过计算出水波纹曲线的所有Y坐标,现曲Y点向控件底部画线构成一个水波纹的横面,现对整个横面进行平移再不断重绘达到动态的效果,废话不多说,看代码:
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import com.shouwei.csdn.R;
import com.shouwei.csdn.util.DensityUtils;
/**
* 自定义水波纹控件
*
* @author sw
* @date 2015-7-1
*/
public class MyWaterRipples extends View {
public final static double A = 8;
public final static double CHUXIANG = 0;
public final static double K = 0;
// 波纹上升的高度
public int riseHeight = 0;
// 第一条水波移动速度
private int translate_speed_one = 7;
// 第二条水波移动速度
private int translate_speed_two = 5;
// 总宽度
private int mTotalWidth = 0;
// 总高度
private int mTotalHeight = 0;
// 原始波纹y坐标数组
private float[] mYPositions;
// 第一条波纹y坐标
private float[] mYPositionsOne;
// 第二条波纹Y坐标
private float[] mYPositionsTwo;
// 画笔
private Paint mWavePaint;
private PaintFlagsDrawFilter mDrawFilter;
// 第一条波纹平移的长度
private int YOffsetOne;
// 第二条波纹平移的长度
private int YOffsetTwo;
public MyWaterRipples(Context context, AttributeSet attrs) {
super(context, attrs);
// 将dp转化为px统一不同分辨率下的速度一致
translate_speed_one = DensityUtils.dp2px(context, translate_speed_one);
translate_speed_two = DensityUtils.dp2px(context, translate_speed_two);
// 画笔
mWavePaint = new Paint();
mWavePaint.setColor(getResources().getColor(R.color.seablue));
mWavePaint.setAntiAlias(true);
mDrawFilter = new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG
| Paint.FILTER_BITMAP_FLAG);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// 获得屏幕宽度
mTotalWidth = getWidth();
mTotalHeight = getHeight();
// 保存原始Y坐标数组
mYPositions = new float[mTotalWidth];
// 保存第一条波浪的Y坐标数组
mYPositionsOne = new float[mTotalWidth];
// 保存第二条波浪的Y坐标数组
mYPositionsTwo = new float[mTotalHeight];
// 根据view总宽度得出所有对应的y值
// 正弦函数:y=Asin(ωx+φ)+k
// A:决定峰值(即纵向拉伸压缩的倍数)
// (ωx+φ)——相位,反映变量y所处的状态。
// φ——初相,x=0时的相位;反映在坐标系上则为图像的左右移动。
// k——偏距,反映在坐标系上则为图像的上移或下移。
// ω——角速度, 控制正弦周期(单位角度内震动的次数)。
// 将周期定为view总宽度
for (int i = 0; i < mTotalWidth; i++) {
mYPositions[i] = (float) (A
* Math.sin(((float) (2 * Math.PI / mTotalWidth)) * i
+ CHUXIANG) + K);
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
resetYPosition();
Log.i("savion", "ondraw----------");
// 从canvas层面去除绘制时锯齿
canvas.setDrawFilter(mDrawFilter);
if (mTotalWidth != 0) {
for (int i = 0; i < mTotalWidth; i++) {
// 减400只是为了控制波纹绘制的y的在屏幕的位置,大家可以改成一个变量,然后动态改变这个变量,从而形成波纹上升下降效果
// 绘制第一条水波纹
canvas.drawLine(i, mTotalHeight - mYPositionsOne[i]
- riseHeight, i, mTotalHeight, mWavePaint);
canvas.drawLine(i, mTotalHeight - mYPositionsTwo[i]
- riseHeight, i, mTotalHeight, mWavePaint);
}
}
YOffsetOne += translate_speed_one;
YOffsetTwo += translate_speed_two;
if (YOffsetOne >= mTotalWidth) {
YOffsetOne = 0;
}
if (YOffsetTwo >= mTotalWidth) {
YOffsetTwo = 0;
}
postInvalidate();
}
private void resetYPosition() {
// 第一条水波纹
int restLengthone = mYPositions.length - YOffsetOne;
// 复制mYPosition数组中yoffsetone位置开始的元素到mYPositionsone数组中0位置,长度为restLenghtOne个
System.arraycopy(mYPositions, YOffsetOne, mYPositionsOne, 0,
restLengthone);
// 复制mYPosition数组中0位置开始的元素到mYPositionsone数组中restLenghtOne位置,长度为YOffsetOne个
System.arraycopy(mYPositions, 0, mYPositionsOne, restLengthone,
YOffsetOne);
// 第二条水波纹
int restLenghttwo = mYPositions.length - YOffsetTwo;
System.arraycopy(mYPositions, YOffsetTwo, mYPositionsTwo, 0,
restLenghttwo);
System.arraycopy(mYPositions, 0, mYPositionsTwo, restLenghttwo,
YOffsetTwo);
}
public void setWaterHeight(int height) {
if (mTotalHeight != 0) {
this.riseHeight = mTotalHeight * height / 100;
}
}
interface OnWaterWaveHeightChangeListener {
public void onWaterHeightChange(int height);
}
}
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
resetYPosition();
Log.i("savion", "ondraw----------");
// 从canvas层面去除绘制时锯齿
canvas.setDrawFilter(mDrawFilter);
if (mTotalWidth != 0) {
for (int i = 0; i < mTotalWidth; i++) {
// 减400只是为了控制波纹绘制的y的在屏幕的位置,大家可以改成一个变量,然后动态改变这个变量,从而形成波纹上升下降效果
// 绘制第一条水波纹
canvas.drawLine(i, mTotalHeight - mYPositionsOne[i]
- riseHeight, i, mTotalHeight, mWavePaint);
canvas.drawLine(i, mTotalHeight - mYPositionsTwo[i]
- riseHeight, i, mTotalHeight, mWavePaint);
}
}
YOffsetOne += translate_speed_one;
YOffsetTwo += translate_speed_two;
if (YOffsetOne >= mTotalWidth) {
YOffsetOne = 0;
}
if (YOffsetTwo >= mTotalWidth) {
YOffsetTwo = 0;
}
postInvalidate();
}
最后配合setWaterHright方法可在外部调用对水波纹的高度进行动态设置:
public void setWaterHeight(int height) {
if (mTotalHeight != 0) {
this.riseHeight = mTotalHeight * height / 100;
}
}
最终效果如下: