Android特效专辑(一)——水波纹过渡特效(首页)

也是今天看到的一个特效,感觉挺漂亮的,最近也一直在筹划一个APP,就想把他当做APP的首页,然后加些处理,关于首页APP的特效等我完工了再贴出来吧,现在先把这个特效给分享出来,只是稍微改动了一点点而已。

原地址:http://blog.csdn.net/jdsjlzx/article/details/44601239

先看效果图:

  1. 我们先创建一个UIUtils,转换一些单位
  1. package com.lgl.test;
  2. import android.content.Context;
  3. import android.util.DisplayMetrics;
  4. import android.view.WindowManager;
  5. public class UiUtils {
  6. static public int getScreenWidthPixels(Context context) {
  7. DisplayMetrics dm = new DisplayMetrics();
  8. ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay()
  9. .getMetrics(dm);
  10. return dm.widthPixels;
  11. }
  12. static public int dipToPx(Context context, int dip) {
  13. return (int) (dip * getScreenDensity(context) + 0.5f);
  14. }
  15. static public float getScreenDensity(Context context) {
  16. try {
  17. DisplayMetrics dm = new DisplayMetrics();
  18. ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay()
  19. .getMetrics(dm);
  20. return dm.density;
  21. } catch (Exception e) {
  22. return DisplayMetrics.DENSITY_DEFAULT;
  23. }
  24. }
  25. }
  1. 然后写一个WaterRippleView类继承View
  1. package com.lgl.test;
  2. import android.content.Context;
  3. import android.graphics.Canvas;
  4. import android.graphics.DrawFilter;
  5. import android.graphics.Paint;
  6. import android.graphics.Paint.Style;
  7. import android.graphics.PaintFlagsDrawFilter;
  8. import android.util.AttributeSet;
  9. import android.view.View;
  10. public class WaterRippleView extends View {
  11. // 波纹颜色
  12. private static final int WAVE_PAINT_COLOR = 0x880000aa;
  13. // y = Asin(wx+b)+h
  14. private static final float STRETCH_FACTOR_A = 20;
  15. private static final int OFFSET_Y = 0;
  16. // 第一条水波移动速度
  17. private static final int TRANSLATE_X_SPEED_ONE = 7;
  18. // 第二条水波移动速度
  19. private static final int TRANSLATE_X_SPEED_TWO = 5;
  20. private float mCycleFactorW;
  21. private int mTotalWidth, mTotalHeight;
  22. private float[] mYPositions;
  23. private float[] mResetOneYPositions;
  24. private float[] mResetTwoYPositions;
  25. private int mXOffsetSpeedOne;
  26. private int mXOffsetSpeedTwo;
  27. private int mXOneOffset;
  28. private int mXTwoOffset;
  29. private Paint mWavePaint;
  30. private DrawFilter mDrawFilter;
  31. public WaterRippleView(Context context, AttributeSet attrs) {
  32. super(context, attrs);
  33. // 将dp转化为px,用于控制不同分辨率上移动速度基本一致
  34. mXOffsetSpeedOne = UiUtils.dipToPx(context, TRANSLATE_X_SPEED_ONE);
  35. mXOffsetSpeedTwo = UiUtils.dipToPx(context, TRANSLATE_X_SPEED_TWO);
  36. // 初始绘制波纹的画笔
  37. mWavePaint = new Paint();
  38. // 去除画笔锯齿
  39. mWavePaint.setAntiAlias(true);
  40. // 设置风格为实线
  41. mWavePaint.setStyle(Style.FILL);
  42. // 设置画笔颜色
  43. mWavePaint.setColor(WAVE_PAINT_COLOR);
  44. mDrawFilter = new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG
  45. | Paint.FILTER_BITMAP_FLAG);
  46. }
  47. @Override
  48. protected void onDraw(Canvas canvas) {
  49. super.onDraw(canvas);
  50. // 从canvas层面去除绘制时锯齿
  51. canvas.setDrawFilter(mDrawFilter);
  52. resetPositonY();
  53. for (int i = 0; i < mTotalWidth; i++) {
  54. // 减400只是为了控制波纹绘制的y的在屏幕的位置,大家可以改成一个变量,然后动态改变这个变量,从而形成波纹上升下降效果
  55. // 绘制第一条水波纹
  56. canvas.drawLine(i, mTotalHeight - mResetOneYPositions[i] - 400, i,
  57. mTotalHeight, mWavePaint);
  58. // 绘制第二条水波纹
  59. canvas.drawLine(i, mTotalHeight - mResetTwoYPositions[i] - 400, i,
  60. mTotalHeight, mWavePaint);
  61. }
  62. // 改变两条波纹的移动点
  63. mXOneOffset += mXOffsetSpeedOne;
  64. mXTwoOffset += mXOffsetSpeedTwo;
  65. // 如果已经移动到结尾处,则重头记录
  66. if (mXOneOffset >= mTotalWidth) {
  67. mXOneOffset = 0;
  68. }
  69. if (mXTwoOffset > mTotalWidth) {
  70. mXTwoOffset = 0;
  71. }
  72. // 引发view重绘,一般可以考虑延迟20-30ms重绘,空出时间片
  73. postInvalidate();
  74. }
  75. private void resetPositonY() {
  76. // mXOneOffset代表当前第一条水波纹要移动的距离
  77. int yOneInterval = mYPositions.length - mXOneOffset;
  78. // 使用System.arraycopy方式重新填充第一条波纹的数据
  79. System.arraycopy(mYPositions, mXOneOffset, mResetOneYPositions, 0,
  80. yOneInterval);
  81. System.arraycopy(mYPositions, 0, mResetOneYPositions, yOneInterval,
  82. mXOneOffset);
  83. int yTwoInterval = mYPositions.length - mXTwoOffset;
  84. System.arraycopy(mYPositions, mXTwoOffset, mResetTwoYPositions, 0,
  85. yTwoInterval);
  86. System.arraycopy(mYPositions, 0, mResetTwoYPositions, yTwoInterval,
  87. mXTwoOffset);
  88. }
  89. @Override
  90. protected void onSizeChanged(int w, int h, int oldw, int oldh) {
  91. super.onSizeChanged(w, h, oldw, oldh);
  92. // 记录下view的宽高
  93. mTotalWidth = w;
  94. mTotalHeight = h;
  95. // 用于保存原始波纹的y值
  96. mYPositions = new float[mTotalWidth];
  97. // 用于保存波纹一的y值
  98. mResetOneYPositions = new float[mTotalWidth];
  99. // 用于保存波纹二的y值
  100. mResetTwoYPositions = new float[mTotalWidth];
  101. // 将周期定为view总宽度
  102. mCycleFactorW = (float) (2 * Math.PI / mTotalWidth);
  103. // 根据view总宽度得出所有对应的y值
  104. for (int i = 0; i < mTotalWidth; i++) {
  105. mYPositions[i] = (float) (STRETCH_FACTOR_A
  106. * Math.sin(mCycleFactorW * i) + OFFSET_Y);
  107. }
  108. }
  109. }
  1. 然后你就可以绑定在布局上就可以使用了
  1. <com.lgl.test.WaterRippleView
  2. android:layout_width="fill_parent"
  3. android:layout_height="fill_parent"
  4. />
  1. 是不是感觉特效还可以

Demo下载地址:http://download.csdn.net/detail/qq_26787115/9384803