返回介绍

一 - 水波纹过渡特效(首页)

发布于 2025-02-28 12:56:40 字数 5282 浏览 0 评论 0 收藏 0

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

先看效果图:

我们先创建一个 UIUtils,转换一些单位

package com.lgl.test;

import android.content.Context;
import android.util.DisplayMetrics;
import android.view.WindowManager;

public class UiUtils {

  static public int getScreenWidthPixels(Context context) {
    DisplayMetrics dm = new DisplayMetrics();
    ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay()
        .getMetrics(dm);
    return dm.widthPixels;
  }

  static public int dipToPx(Context context, int dip) {
    return (int) (dip * getScreenDensity(context) + 0.5f);
  }

  static public float getScreenDensity(Context context) {
    try {
      DisplayMetrics dm = new DisplayMetrics();
      ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay()
          .getMetrics(dm);
      return dm.density;
    } catch (Exception e) {
      return DisplayMetrics.DENSITY_DEFAULT;
    }
  }

}

然后写一个 WaterRippleView 类继承 View

package com.lgl.test;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.DrawFilter;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.PaintFlagsDrawFilter;
import android.util.AttributeSet;
import android.view.View;

public class WaterRippleView extends View {

  // 波纹颜色
  private static final int WAVE_PAINT_COLOR = 0x880000aa;
  // y = Asin(wx+b)+h
  private static final float STRETCH_FACTOR_A = 20;
  private static final int OFFSET_Y = 0;
  // 第一条水波移动速度
  private static final int TRANSLATE_X_SPEED_ONE = 7;
  // 第二条水波移动速度
  private static final int TRANSLATE_X_SPEED_TWO = 5;
  private float mCycleFactorW;

  private int mTotalWidth, mTotalHeight;
  private float[] mYPositions;
  private float[] mResetOneYPositions;
  private float[] mResetTwoYPositions;
  private int mXOffsetSpeedOne;
  private int mXOffsetSpeedTwo;
  private int mXOneOffset;
  private int mXTwoOffset;

  private Paint mWavePaint;
  private DrawFilter mDrawFilter;

  public WaterRippleView(Context context, AttributeSet attrs) {
    super(context, attrs);
    // 将 dp 转化为 px,用于控制不同分辨率上移动速度基本一致
    mXOffsetSpeedOne = UiUtils.dipToPx(context, TRANSLATE_X_SPEED_ONE);
    mXOffsetSpeedTwo = UiUtils.dipToPx(context, TRANSLATE_X_SPEED_TWO);

    // 初始绘制波纹的画笔
    mWavePaint = new Paint();
    // 去除画笔锯齿
    mWavePaint.setAntiAlias(true);
    // 设置风格为实线
    mWavePaint.setStyle(Style.FILL);
    // 设置画笔颜色
    mWavePaint.setColor(WAVE_PAINT_COLOR);
    mDrawFilter = new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG
        | Paint.FILTER_BITMAP_FLAG);
  }

  @Override
  protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    // 从 canvas 层面去除绘制时锯齿
    canvas.setDrawFilter(mDrawFilter);
    resetPositonY();
    for (int i = 0; i < mTotalWidth; i++) {

      // 减 400 只是为了控制波纹绘制的 y 的在屏幕的位置,大家可以改成一个变量,然后动态改变这个变量,从而形成波纹上升下降效果
      // 绘制第一条水波纹
      canvas.drawLine(i, mTotalHeight - mResetOneYPositions[i] - 400, i,
          mTotalHeight, mWavePaint);

      // 绘制第二条水波纹
      canvas.drawLine(i, mTotalHeight - mResetTwoYPositions[i] - 400, i,
          mTotalHeight, mWavePaint);
    }

    // 改变两条波纹的移动点
    mXOneOffset += mXOffsetSpeedOne;
    mXTwoOffset += mXOffsetSpeedTwo;

    // 如果已经移动到结尾处,则重头记录
    if (mXOneOffset >= mTotalWidth) {
      mXOneOffset = 0;
    }
    if (mXTwoOffset > mTotalWidth) {
      mXTwoOffset = 0;
    }

    // 引发 view 重绘,一般可以考虑延迟 20-30ms 重绘,空出时间片
    postInvalidate();
  }

  private void resetPositonY() {
    // mXOneOffset 代表当前第一条水波纹要移动的距离
    int yOneInterval = mYPositions.length - mXOneOffset;
    // 使用 System.arraycopy 方式重新填充第一条波纹的数据
    System.arraycopy(mYPositions, mXOneOffset, mResetOneYPositions, 0,
        yOneInterval);
    System.arraycopy(mYPositions, 0, mResetOneYPositions, yOneInterval,
        mXOneOffset);

    int yTwoInterval = mYPositions.length - mXTwoOffset;
    System.arraycopy(mYPositions, mXTwoOffset, mResetTwoYPositions, 0,
        yTwoInterval);
    System.arraycopy(mYPositions, 0, mResetTwoYPositions, yTwoInterval,
        mXTwoOffset);
  }

  @Override
  protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    // 记录下 view 的宽高
    mTotalWidth = w;
    mTotalHeight = h;
    // 用于保存原始波纹的 y 值
    mYPositions = new float[mTotalWidth];
    // 用于保存波纹一的 y 值
    mResetOneYPositions = new float[mTotalWidth];
    // 用于保存波纹二的 y 值
    mResetTwoYPositions = new float[mTotalWidth];

    // 将周期定为 view 总宽度
    mCycleFactorW = (float) (2 * Math.PI / mTotalWidth);

    // 根据 view 总宽度得出所有对应的 y 值
    for (int i = 0; i < mTotalWidth; i++) {
      mYPositions[i] = (float) (STRETCH_FACTOR_A
          * Math.sin(mCycleFactorW * i) + OFFSET_Y);
    }
  }
}

然后你就可以绑定在布局上就可以使用了

<com.lgl.test.WaterRippleView
   android:layout_width="fill_parent"
   android:layout_height="fill_parent"
   />

是不是感觉特效还可以

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文