Android自定义WaveProgressView实现水波纹加载需求

作者:amazing7 时间:2021-07-29 02:06:00 

先看效果图:

Android自定义WaveProgressView实现水波纹加载需求

你可以定义成你项目的logo图片,可以设置水波颜色、波长、波宽、字体大小、颜色、进度条的最大值,当前进度值,还可以设置波纹震动的快慢。当设置一个进度不变的时候,打开时还有一个动画填满的效果(比如第二个流量显示,这里图片没有截出这个效果)。

源码地址

1. 如何使用

1.1 在布局文件中

添加自定义控件:


<cn.fanrunqi.waveprogressview.WaveProgressView
android:id="@+id/waveProgressbar"
android:background="@drawable/circle"
<!--android:background="@drawable/bg_a"-->
android:layout_width="130dp"
android:layout_height="130dp" />

说明,这里的android:background定义的是控件的形状,比如上面的圆形和美女,你可用shape.xml定义形状图片。

比如,这是一个圆


<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="#DDDDDD"/>
<size android:width="150dp"
android:height="150dp"/>
</shape>

也可以直接给android:background设置一张图片,比如:

Android自定义WaveProgressView实现水波纹加载需求

这里注意透明像素,还有为了图片缩放的时候不变形,建议背景(不管是图片还是图形)为正方形。

1.2 在代码中

你可以选择进行如下设置:


//设置当前进度值和当前显示的文字
waveProgressbar.setCurrent(int currentProgress,String currentText); // 77, "788M/1024M"
//设置进度条的最大值
waveProgressbar.setMaxProgress(int maxProgress);
//设置显示文字的大小和颜色
waveProgressbar.setText(String mTextColor,int mTextSize);//"#FFFF00", 41
//设置水波的颜色
waveProgressbar.setWaveColor(String mWaveColor); //"#5b9ef4"
//设置波浪的高度和波浪的宽度(均为一个波峰的大小)
waveProgressbar.setWave(float mWaveHight,float mWaveWidth);
//设置波浪的上下震动的速度(这里注意值越大,震动的越小)
waveProgressbar.setmWaveSpeed(int mWaveSpeed);//The larger the value, the slower the vibration

2. 代码实现

这里实现主要用到的知识有 自定义view、PorterDuffXfermode和二阶贝塞尔曲线,不太清楚的可以在我博客找找,都有的。
首先自定义WaveProgressView继承View,在构造函数中获取布局文件中设置的背景,同时设置一个画波浪的画笔和画文字的画笔。


private void Init() {
/**
* 获得背景
*/
if(null==getBackground()){
throw new IllegalArgumentException(String.format("background is null."));
}else{
backgroundBitmap = getBitmapFromDrawable(getBackground());
}
/**
* 波浪画笔
*/
mPath = new Path();
mPathPaint = new Paint();
mPathPaint.setAntiAlias(true);
mPathPaint.setStyle(Paint.Style.FILL);
/**
* 进度画笔
*/
mTextPaint = new Paint();
mTextPaint.setAntiAlias(true);
mTextPaint.setTextAlign(Paint.Align.CENTER);
//开始不断自我绘制,让波浪动起来
handler.sendEmptyMessageDelayed(INVALIDATE,100);
}

复写onDraw方法,先把波浪画在画布上,然后画背景(给背景画笔设置PorterDuff.Mode.DST_ATOP模式:取上层非交集部分与下层交集部分 )。当然也可以是PorterDuff.Mode.SRC_ATOP,主要取决于你画的先后顺序。最后把文字画上去,形成一个最终Bitmap,最后把这个Bitmap画到onDraw的参数canvas上。


Paint paint = new Paint();
paint.setAntiAlias(true);
Bitmap finalBmp = Bitmap.createBitmap(width,height, Bitmap.Config.ARGB_8888);
/**
* 产生一个同样大小的画布
*/
Canvas canvas = new Canvas(finalBmp);
/**
* 绘制波浪
*/
float CurMidY = height*(maxProgress-currentProgress)/maxProgress;
if(CurY>CurMidY){
CurY = CurY - (CurY-CurMidY)/10;
}
mPath.reset();
mPath.moveTo(0-distance,CurY);

int waveNum = width/((int)mWaveHalfWidth*4)+1;
int multiplier = 0;
for(int i =0;i<waveNum;i++){
mPath.quadTo(mWaveHalfWidth*(multiplier+1)-distance,CurY-mWaveHight,mWaveHalfWidth*(multiplier+2)-distance,CurY);
mPath.quadTo(mWaveHalfWidth*(multiplier+3)-distance,CurY+mWaveHight,mWaveHalfWidth*(multiplier+4)-distance,CurY);
multiplier+=4;
}
distance +=mWaveHalfWidth/mWaveSpeed;
distance = distance%(mWaveHalfWidth*4);

mPath.lineTo(width,height);
mPath.lineTo(0,height);
mPath.close();
canvas.drawPath(mPath, mPathPaint);
/**
* 对图片给进行缩放
*/
int min = Math.min(width,height);
backgroundBitmap = Bitmap.createScaledBitmap(backgroundBitmap,min,min,false);
/**
* 使用DST_ATOP,取上层非交集部分与下层交集部分 。
*/
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP));
/**
* 绘制图片
*/
canvas.drawBitmap(backgroundBitmap,0,0,paint);
/**
* 绘制进度文字
*/
canvas.drawText(currentText, width/2, height/2, mTextPaint);
return finalBmp;

这里的CurY是上次波浪中线的y轴坐标,CurMidY 是当前的Y轴坐标,每次波浪上升的时候为了不产生卡顿效果,把这1/100的上升分为10次来绘制。
distance是x轴的偏移量,为了使水波动起来,每次绘制时都要向左进行一段偏移。


distance +=mWaveHalfWidth/mWaveSpeed;
distance = distance%(mWaveHalfWidth*4);

每次偏移距离为半波宽度/波浪震动速度,因为一个波是4个半波宽度形成一个循环,然后又回到最开始x位置开始循环位移。
根据view的宽度计算出一共要绘制多少个波形出来,同时多加一个波为了向左平移。


int waveNum = width/((int)mWaveHalfWidth*4)+1;
int multiplier = 0;
for(int i =0;i<waveNum;i++){
 mPath.quadTo(mWaveHalfWidth*(multiplier+1)-distance,CurY-mWaveHight,mWaveHalfWidth*(multiplier+2)-distance,CurY);
 mPath.quadTo(mWaveHalfWidth*(multiplier+3)-distance,CurY+mWaveHight,mWaveHalfWidth*(multiplier+4)-distance,CurY);
 multiplier+=4;
}

每次绘制以波形的左边点、波形的右边点、view的左下角、view的右下角、形成一个图片把它绘制到内存中新建的和view同大小的canvas上。


mPath.reset();
mPath.moveTo(0-distance,CurY);

mPath.lineTo(width,height);
mPath.lineTo(0,height);
mPath.close();
canvas.drawPath(mPath, mPathPaint);

先对背景图形进行缩放再绘制到canvas上,这里的缩放是按最小边进行缩放。


int min = Math.min(width,height);
backgroundBitmap = Bitmap.createScaledBitmap(backgroundBitmap,min,min,false);

最后把文字绘制上去,注意我们在初始化中设置了画笔,为了能通过代码设置文字的颜色,要把设置文字画笔颜色和大小放在onDraw方法中。


mPathPaint.setColor(Color.parseColor(mWaveColor));
mTextPaint.setColor(Color.parseColor(mTextColor));
mTextPaint.setTextSize(mTextSize);
canvas.drawText(currentText, width/2, height/2, mTextPaint);

为了使波浪动起来,使用handler循环调用invalidate刷新界面。同时应该在构造函数打开handler循环。


private static final int INVALIDATE = 0X777;
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
 super.handleMessage(msg);
 switch (msg.what) {
 case INVALIDATE:
  invalidate();
  sendEmptyMessageDelayed(INVALIDATE,RefreshGap);
  break;
 }
}
};

最后就是一些相关属性设置的函数。


/**
* @param currentProgress 当前进度
* @param currentText 当前显示的进度文字
*/
public void setCurrent(int currentProgress,String currentText) {
this.currentProgress = currentProgress;
this.currentText = currentText;
}

/**
* @param maxProgress 设置进度条的最大值,默认100
*/
public void setMaxProgress(int maxProgress){
this.maxProgress = maxProgress;
}

/**
* @param mTextColor 文字的颜色
* @param mTextSize 文字的大小
*/
public void setText(String mTextColor,int mTextSize){
this.mTextColor = mTextColor;
this.mTextSize = mTextSize;
}
/**
* @param mWaveHight 波峰的高度
* @param mWaveWidth 一个波峰的宽度
*/
public void setWave(float mWaveHight,float mWaveWidth){
this.mWaveHight = mWaveHight;
this.mWaveHalfWidth = mWaveWidth/2;
}

/**
* @param mWaveColor 水的颜色
*/
public void setWaveColor(String mWaveColor){
this.mWaveColor = mWaveColor;
}
/**
* 值越大震荡的越慢
* @param mWaveSpeed
*/
public void setmWaveSpeed(int mWaveSpeed){
this.mWaveSpeed = mWaveSpeed;
}

实现还是比较简单的,源码和demo都在上面的地址中,如果有什么问题可以给我留言,谢谢!

来源:http://blog.csdn.net/amazing7/article/details/51855165

标签:Android,WaveProgressView,水波纹
0
投稿

猜你喜欢

  • Flink开发IDEA环境搭建与测试的方法

    2023-02-21 21:20:46
  • Android简单音乐播放实例

    2023-04-13 05:49:55
  • 关于Android的 DiskLruCache磁盘缓存机制原理

    2022-12-16 16:57:43
  • C#判断一个字符串是否是数字或者含有某个数字的方法

    2022-05-07 14:38:17
  • Unity的OnOpenAsset实用案例深入解析

    2021-05-30 01:37:16
  • C#中的Linq To XML讲解

    2021-06-29 18:39:43
  • 关于maven使用过程中无法导入依赖的一些总结

    2021-12-16 01:51:20
  • 通过Session案例分析一次性验证码登录

    2023-04-27 06:25:51
  • Android App仿QQ制作Material Design风格沉浸式状态栏

    2021-06-07 01:10:48
  • .NET/C#实现识别用户访问设备的方法

    2021-12-20 06:30:58
  • SpringBoot 配置文件总结

    2021-09-06 13:12:57
  • java之函数式接口解读

    2022-07-16 16:32:46
  • 基于Java Socket实现一个简易在线聊天功能(一)

    2023-09-23 17:18:35
  • Android支付宝支付开发实例

    2023-01-01 09:15:18
  • springboot max-http-header-size最大长度的那些事及JVM调优方式

    2021-12-14 03:43:46
  • Prometheus 入门教程之SpringBoot 实现自定义指标监控

    2022-08-02 12:58:54
  • 基于Mybatis映射的一点心得(分享)

    2023-08-08 13:15:53
  • Kotlin中的对象表达式和对象声明的具体使用

    2022-05-31 04:08:18
  • 详解Android四种存储方式

    2022-06-26 21:51:35
  • Android自定义ViewGroup实现可滚动的横向布局(2)

    2022-10-08 17:25:27
  • asp之家 软件编程 m.aspxhome.com