Android自定义view实现水波进度条控件

通过自定义view实现了一个水滴滴落到水波面,溅起水花并且水波流动上涨的进度条控件。之前看到过好多水波流动的进度条,感觉欠缺些东西,就想到了水滴到水平面,溅起水花然后水流动上涨的进度条效果,于是自己动手写了出来。效果如下,视频录制有些卡顿,实际会流畅很多。

一.用法

1.布局文件中添加WaveProgressView,circleColor属性为圆环颜色,waterColor属性为水波水滴的颜色,progress属性为初始的进度

<com.yhongm.wave_progress_view.WaveProgressView
  android:id="@+id/wave_progress_view"
  android:layout_width="300dp"
  android:layout_height="300dp"
  android:layout_centerInParent="true"
  app:circleColor="#e38854"
  app:progress="0"
  app:waterColor="#5488e3" />

2.WaveProgressView.setProgress()方法设置当前的进度

二.本文实现的逻辑

1,画水波流动,通过三阶贝塞尔曲线画波形,通过不断的改变waveOffsetX和waveOffsetY的值实现流动的效果

/**
   * 生成水波流动
   *
   * @param begin    水波形开始的位置
   * @param waveLength 水波的长度
   * @param waveOffsetX 水波水平的偏移
   * @param waveOffsetY 水波垂直方向的偏移
   * @return
   */
  private Path getWavePath(float begin, int waveLength, int waveOffsetX, int waveOffsetY) {
    Path mPath = new Path();
    mPath.reset();
    mPath.moveTo(waveLength * begin, mCurrentHeight);
    for (int i = 0; i < mWaveCount; i++) {
      mPath.quadTo(waveLength * (begin + 0.25f) + (i * waveLength) + waveOffsetX, mCurrentHeight + waveOffsetY, (waveLength * (begin + 0.5f) + (i * waveLength) + waveOffsetX), mCurrentHeight);
      mPath.quadTo(waveLength * (begin + 0.75f) + (i * waveLength) + waveOffsetX, mCurrentHeight - waveOffsetY, (waveLength * (begin + 1f) + (i * waveLength) + waveOffsetX), mCurrentHeight);
    }
    mPath.lineTo(mWidth, mHeight);
    mPath.lineTo(0, mHeight);
    mPath.close();
    return mPath;
  } 

2.画水滴的形状,水滴的形状是通过一个三角形和一个弧形组成的

/**
   * 水滴的Path
   *
   * @param x  水滴坐标x
   * @param y  水滴坐标y
   * @param size 水滴尺寸
   * @return
   */
  private Path waterDrop(float x, float y, int size) {
    Path mDropPath = new Path();
    mDropPath.moveTo(x - size, y);
    mDropPath.lineTo(x, (float) (y - size * 2.5));
    mDropPath.lineTo(x + size, y);
    mDropPath.addArc(x - size, y - size, x + size, y + size, 0, 180);
    return mDropPath;
  }

3.画水滴滴落到水波的效果,就是沿轴Y轴不断的移动水滴

/**
   * 根据位置画水滴
   *
   * @param x
   * @param y
   * @param canvas
   */
  private void drawDropByLocation(Canvas canvas, int x, int y) {
    Path mDropPath = waterDrop(x, y, 30);
    if (y == (mCurrentHeight + 50)) {
      mDropPaint.setAlpha(0);
    }
    canvas.drawPath(mDropPath, mDropPaint);
  }

4.画最外两侧溅落的水滴,通过三阶贝塞尔曲线模拟左右两侧水滴溅落的路径,随机生成的水滴溅落路径都在这左右两侧内

/**
   * 画两侧水滴飞溅的效果,并且随机生成水滴
   *
   * @param canvas
   * @param x
   * @param y   当前高度
   */
  private synchronized void drawDropSplash(Canvas canvas, int x, int y) {
    PathMeasure mLeftPathMeasure = getOnBothSidesOfPathMeasure(x, y, true);
    PathMeasure mRightPathMeasure = getOnBothSidesOfPathMeasure(x, y, false);

    float[] mLeftPos = new float[2];
    float[] mRightPos = new float[2];
    float[] mLeftTan = new float[2];
    float[] mRightTan = new float[2];

    for (int i = 0; i < 200; i++) {
      float percent = i / 200f;
      mLeftPathMeasure.getPosTan(mLeftPathMeasure.getLength() * percent, mLeftPos, mLeftTan);
      mRightPathMeasure.getPosTan(mRightPathMeasure.getLength() * percent, mRightPos, mRightTan);
      mLeftHashMapPath.put(Math.round(mLeftPos[1]), mLeftPos[0]);
      mRightHashMapPath.put(Math.round(mRightPos[1]), mRightPos[0]);
    }

    if (mRandomHashMap.isEmpty() && mRandomHashMap.size() == 0) {
      pushRandomDrag(y);
    }
    drawRandomDrag(canvas, x, y, mLeftHashMapPath, mRightHashMapPath);

    drawOnBothSidesOfWaterDrop(canvas, mLeftPathMeasure);

    drawOnBothSidesOfWaterDrop(canvas, mRightPathMeasure);

}
/**
   * 产生随机的水滴
   *
   * @param y
   */
  private void pushRandomDrag(int y) {
    Random r = new Random();
    for (int i = 0; i < 20; i++) {
      int randomY = r.nextInt(y);
      if (mLeftHashMapPath.containsKey(randomY)) {
        Float rightValue = mRightHashMapPath.get(randomY);
        Float leftValue = mLeftHashMapPath.get(randomY);
        int roundLeftValue = Math.round(leftValue);
        int roundRightValue = Math.round(rightValue);
        if (roundRightValue == roundLeftValue) {
          roundRightValue++;
        }
        int roundMinus = Math.round(roundRightValue - roundLeftValue);//左右差值
        float randomX = r.nextInt(roundMinus) + mLeftHashMapPath.get(randomY);//左右差值加上最小值,保证随机值在两者之间
        mRandomHashMap.put(randomX, randomY);

      }
    }
}

5.随机生成的水滴沿着三阶贝塞尔曲线移动,形成溅落的效果

/**
   * 画随机生成水滴溅起
   *
   * @param canvas
   * @param x
   * @param y
   * @param size
   * @param randomY
   * @param randomX
   */
  private void drawSmartDropOnPath(Canvas canvas, int x, int y, int size, int randomY, float randomX) {
    Path smartDropPath = new Path();
    smartDropPath.moveTo(x, y + 50);
    if (x < randomX) {
      smartDropPath.cubicTo(x, y + 50, randomX + 30, randomY - 20, randomX, randomY);
    } else {
      smartDropPath.cubicTo(x, y + 50, randomX - 30, randomY - 20, randomX, randomY);
    }
    smartDropPath.lineTo(randomX, randomY + 150);
    PathMeasure pathMeasure = new PathMeasure();
    pathMeasure.setPath(smartDropPath, false);
    float[] pos = new float[2];
    float[] tan = new float[2];
    pathMeasure.getPosTan(pathMeasure.getLength() * mPercent, pos, tan);
    Path path = waterDrop(pos[0], pos[1], size);
    canvas.drawPath(path, mSplashPaint);
  }

完整代码详见 点击打开Github本项目 感兴趣的话帮我点个Star

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • android实现快递跟踪进度条

    本文实例为大家分享了android快递跟踪进度条展示的具体代码,供大家参考,具体内容如下 activity.class import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import android.app.Activity; import android.os.Bundle; import android.widget.ListView; publ

  • android ListView和ProgressBar(进度条控件)的使用方法

    ListView控件的使用:ListView控件里面装的是一行一行的数据,一行中可能有多列,选中一行,则该行的几列都被选中,同时可以触发一个事件,这种控件在平时还是用得很多的.使用ListView时主要是要设置一个适配器,适配器主要是用来放置一些数据.使用起来稍微有些复杂,这里用的是android自带的SimpleAdapter,形式如下:android.widget.SimpleAdapter.SimpleAdapter(Context context, List<? extends Map<

  • Android自定义View实现加载进度条效果

    上一篇文章总结了下自定义View的几个步骤,如果还有不清楚的同学可以先去看看Android自定义View(一),这篇文章和大家分享一下自定义加载进度条,效果如下 下面就以水平的进度条为列进行讲解: 1.首先还是在attrs.xml文件中自定义我们需要的属性: <?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="GradientP

  • android自定义进度条渐变色View的实例代码

    最近在公司,项目不是很忙了,偶尔看见一个兄台在CSDN求助,帮忙要一个自定义的渐变色进度条,我当时看了一下进度条,感觉挺漂亮的,就尝试的去自定义view实现了一个,废话不说,先上图吧! 这个自定义的view,完全脱离了android自带的ProgressView,并且没使用一张图片,这样就能更好的降低程序代码上的耦合性! 下面我贴出代码  ,大概讲解一下实现思路吧! 复制代码 代码如下: package com.spring.progressview; import android.conten

  • Android中实现Webview顶部带进度条的方法

    写这篇文章,做份备忘,简单滴展示一个带进度条的Webview示例,进度条位于Webview上面. 示例图如下: 主Activity代码: 复制代码 代码如下: package com.droidyue.demo.webviewprogressbar; import android.app.Activity; import android.os.Bundle; import android.view.Menu; import android.view.View; import android.vi

  • Android仿微信公众号文章页面加载进度条

    前言: 微信公众号文章详情页面加载的时候,WebView会在头部显示一个进度条,这样做的好处就是用户可以一边加载网页内容的同时也可浏览网页内容,不需要等完全加载完之后才全部显示出来.如何实现呢? 其实很简单,自定义一个WebView就可以实现了. 详细实现步骤如下 : 1.自定义一个ProgressWebView 继续 Webview @SuppressWarnings("deprecation") public class ProgressWebView extends WebVie

  • Android自定义View实现渐变色进度条

    在网上看到一个进度条效果图,非常美观,如下: 进行效果分解: 1.渐变色,看起来颜色变化并不复杂,使用LinearGradient应该可以实现. 2.圆头,无非是画两个圆,外圆使用渐变色的颜色,内圆固定为白色. 3.灰底,还没有走到的进度部分为灰色. 4.进度值,使用文本来显示: 5.弧形的头部,考虑使用直线进行连接,或者使用曲线,例如贝塞尔曲线: 我首先初步实现了进度条的模样,发现样子有了,却不太美观. 反思了一下,我只是个写代码的,对于哪种比例比较美观,是没有清晰的认识的,所以,还是参考原图

  • Android 七种进度条的样式

    当一个应用在后台执行时,前台界面就不会有什么信息,这时用户根本不知道程序是否在执行.执行进度如何.应用程序是否遇到错误终止等,这时需要使用进度条来提示用户后台程序执行的进度.Android系统提供了两大类进度条样式,长形进度条(progress-BarStyleHorizontal) 和圆形进度条(progressBarStyleLarge).进度条用处很多,比如,应用程序装载资源和网络连接时,可以提示用户稍等,这一类进度条只是代表应用程序中某一部分的执行情况,而整个应用程序执行情况呢,则可以通

  • Android文件下载进度条的实现代码

    main.xml: 复制代码 代码如下: <?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:orientation="vertical"    android:layout_width="fill_paren

  • Android仿微信加载H5页面进度条

    前言 Android中WebView打卡前端页面时受到网路环境,页面内容大小的影响有时候会让用户等待很久.显示一个加载进度条可以提升很大的体验.微信内访问H5页面加载效果不错,效仿着写了一个. 1.实现 1-1.自定义类继承WebView类 class ProgressWebView(context: Context, attr: AttributeSet) : WebView(context, attr) { /** *xml布局中使用,所以用两个构造参数的构造函数 */ private va

随机推荐