Android项目实战手把手教你画圆形水波纹loadingview
作者:菜鸡wing 发布时间:2023-03-15 10:13:47
本文实例讲解的是如何画一个满满圆形水波纹loadingview,这类效果应用场景很多,比如内存占用百分比之类的,分享给大家供大家参考,具体内容如下
效果图如下:
预备的知识:
1.贝塞尔曲线 如果你不了解,可以来这里进行基础知识储备:神奇的贝塞尔曲线
2.Paint.setXfermode()以及PorterDuffXfermode
千万不要被这个b的名字吓到,不熟悉看到可能会认为很难记,其实 只要站在巨人的丁丁上 还是很简单的。
好了 废话不多说 ,跟我一步步来做一个炫酷的view吧。
首先给一些属性,在构造器里初始化(不要再ondraw new东西不要再ondraw new东西不要再ondraw new东西不要再ondraw new东西)
//绘制波纹
private Paint mWavePaint;
private PorterDuffXfermode mMode = new PorterDuffXfermode(PorterDuff.Mode.XOR);//设置mode 为XOR
//绘制圆
private Paint mCirclePaint;
private Canvas mCanvas;//我们自己的画布
private Bitmap mBitmap;
private int mWidth;
private int mHeight;
public WaveLoadingView(Context context) {
this(context,null);
}
public WaveLoadingView(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public WaveLoadingView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mWavePaint = new Paint();
mWavePaint.setColor(Color.parseColor("#33b5e5"));
mCirclePaint = new Paint();
mCirclePaint.setColor(Color.parseColor("#99cc00"));
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
if (widthMode == MeasureSpec.EXACTLY) {
mWidth = widthSize;
}
if (heightMode == MeasureSpec.EXACTLY) {
mHeight = heightSize;
}
setMeasuredDimension(mWidth, mHeight);
mBitmap = Bitmap.createBitmap(300,300, Bitmap.Config.ARGB_8888); //生成一个bitmap
mCanvas = new Canvas(mBitmap);//讲bitmp放在我们自己的画布上,实际上mCanvas.draw的时候 改变的是这个bitmap对象
}
然后,我们给他绘制一点东西,用来介绍PorterDuffXfermode
@Override
protected void onDraw(Canvas canvas) {
mCanvas.drawCircle(100,100,50,mCirclePaint);
mCanvas.drawRect(100,100,200,200,mWavePaint);
canvas.drawBitmap(mBitmap,0,0,null);
super.onDraw(canvas);
}
嗯,可以看到 是我们现在自己的画布上铺了一个bitmap(这里可以理解canvas为桌子 bitmap为画纸,我们在bimap上画画), 然后在bitmap上画了 一个圆,和一个矩形。最后把我们的mBitmap画到系统的画布上(显示到屏幕上),得到了以下效果。
然后我们用setXfermode()方法给他设置一个mode,这里设置XOR。
可以发现! 相交的地方消失了! 是不是很神奇。
在改一个mode 试试
private PorterDuffXfermode mMode = new PorterDuffXfermode(PorterDuff.Mode.DST_OVER);
可以看到圆形跑到了矩形上面来。然后巨人给我们总结各个模式如了下图,这里给一个说明dst为先画的 src为后画的:.
大家可以根据这个规律试一下。
现在,我们把圆和矩形重叠。模式去掉。
protected void onDraw(Canvas canvas) {
//dst
mCanvas.drawCircle(150,150,50,mCirclePaint);
/ mWavePaint.setXfermode(mMode);
//src
mCanvas.drawRect(100,100,200,200,mWavePaint);
canvas.drawBitmap(mBitmap,0,0,null);
super.onDraw(canvas);
}
我的圆怎么没了。。 其实圆是被覆盖掉了。 然后我们想实现一个效果,就是在圆的范围内,显示矩形的内容,该怎么做呢。自己照着图找找吧哈哈。
我们要实现的是一个圆形的水波纹那种loadingview。。首要就是实现这个水波纹。
这时候贝塞尔曲线就派上用场了。这里采用三阶贝塞尔, 不停地改变X 模拟水波效果。
if (x > 50) {
isLeft = true;
} else if (x < 0) {
isLeft = false;
}
<span style="white-space:pre"> </span>if (y > -50) { //大于-50是因为辅助点是50 为了让他充满整个屏幕
y--;
} if (isLeft) {
x = x - 1;
} else {
x = x + 1;
}
mPath.reset();
mPath.moveTo(0, y);
mPath.cubicTo(100 + x*2, 50 + y, 100 + x*2, y-50, mWidth, y);//前两个参数是辅助点
mPath.lineTo(mWidth, mHeight);//充满整个画布
mPath.lineTo(0, mHeight);//充满整个画布
mPath.close();
之后用mCanvas来绘制这个bitmap,要注意的是 绘制之前要清空mBitmap,不然path会重叠
mBitmap.eraseColor(Color.parseColor("#00000000"));
//dst
mCanvas.drawPath(mPath, mPaint);
canvas.drawBitmap(mBitmap, 0, 0, null);
postInvalidateDelayed(10);
哈,水波效果出来了。接着想办法让他画到一个圆形中。 首先绘制一个圆
mCanvas.drawCircle(mWidth / 2, mHeight / 2, mWidth / 2, mSRCPaint);
现在让我们回到刚才的问题,如何在dst的范围内绘制src呢。答案是:SRC_IN 你找对了吗?添加模式
//dst
mCanvas.drawCircle(mWidth / 2, mHeight / 2, mWidth / 2, mSRCPaint);
mPaint.setXfermode(mMode);
//src
mCanvas.drawPath(mPath, mPaint);
canvas.drawBitmap(mBitmap, 0, 0, null);
是不是有点感觉了。如果不这样做 就需要考虑好多问题。动态计算沿着圆弧x,y坐标计算arcTo的范围。
完善一下,添加一个percent来代表进度,让y来根据percent动态改变
y = (int) ((1-mPercent /100f) *mHeight);
添加setPercent方法
public void setPercent(int percent){
mPercent = percent;
}
画上百分比的文字。
String str = mPercent + "%";
float txtLength = mTextPaint.measureText(str);
canvas.drawText(mPercent + "%", mWidth / 2-txtLength/2, mHeight / 2, mTextPaint);
然后配合seekBar,最后改改字体大小 画笔透明度。 添加个背景图 就成了效果图上的效果。
是不是很有趣,大家可以动手实现一下!


猜你喜欢
- Collection 接口 :Collection是最基本的集合接口,声明了适用于JAVA集合(只包括Set和List)的通用方法。Set和
- Android对这种方法进行了封装,我们没有权限去调用这个方法,所以我们只能通过AIDL,然后利用Java的反射机制去调用系统级的方法。下面
- 目前的设计中是支持单体声和立体声自动切换的。切换是需要在一定的条件下满足才会进行切换,切换的条件和电台的信号强度RSSI、信号稳定性CQI等
- OpenFeign介绍一开始,我们使用原生的 DiscoveryClient 发现服务和使用RestTemplate进行服务间调用,然后我们
- Java%(取模运算)Java的取模运算1.实现算法public static double ramainder(double divide
- 这个是基于SystemBarTintManager更改的增加一个方法:用于更改MIUIV6系统上的状态栏字体颜色 ,目前我仅仅只发现MIUI
- 我就废话不多说了,大家还是直接看代码吧!public static String mapToTxt(Map<String,String
- 前一段时间,在做摄像头拍照上传,摄像头拍的照片为base64编码格式的字符串,需要上传至项目中,则需要使用到将base64编码字符串转换为图
- 一、DataGridView不显示下面的新行通常DataGridView的最下面一行是用户新追加的行(行头显示*)。如果不想让用户新追加行即
- 最近在搞一个购物车的功能,里面有一个批量删除的操作,采用的是ExpandableListView以及BaseExpandableListAd
- java联调生成测试数据工具类在日常的联调中,我们经常需要准备一定数量的测试数据,用来配合前端测试。当然对于简单的数据类型完全可以通过 JD
- JSON字符串和java对象的互转【json-lib】在开发过程中,经常需要和别的系统交换数据,数据交换的格式有XML、JSON等,JSON
- 目录一、基础配置1、<parent> 标签1)使用 spring-boot-starter-parent2)使用自定义 pare
- 1.发生问题的场景我在用java获取一个接口的大JSON字符串,并赋值给String常量时,遇到了java: 常量字符串过长这个报错2.解决
- 首先,我们使用使用命令创建模板项目,创建的命令如下。taro init myApp然后,使用 yarn 或者 npm install安装依赖
- 这篇文章主要介绍了通过实例解析java8中的parallelStream,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考
- 本文实例为大家分享了C#实现QQ聊天窗口的具体代码,供大家参考,具体内容如下效果图:using System;using System.Co
- Android中的消息处理机制大量依赖于Handler。每个Handler都有对应的Looper,用于不断地从对应的MessageQueue
- 注解定义: 注解是一种注释机制,它可以注释包、类、方法、变量、参数,在编译器生成类文件时,标注可以被嵌入到字节码中。注解的分类:内置注解Ov
- 小背景:我们公司项目中的小脚本是一些工具类,比如常用的是MapUtil工具类的一些方法写公司的MapUtil工具类的方法要注意,方法名的命名