android 进度条_Android仿水波纹流球进度条控制器,实现高端大气的主流特效

今天看到一个效果挺不错的,就模仿了下来,加上了一些自己想要的效果,感觉还不错的样子,所以就分享出来了,话不多说,上图

05bb7f68d7884b4ab3c7ce6baae00167

CircleView

这里主要是实现中心圆以及水波特效

package com.lgl.circleview;

import android.content.Context;

import android.graphics.Canvas;

import android.graphics.Color;

import android.graphics.Paint;

import android.graphics.Path;

import android.graphics.RectF;

import android.os.Handler;

import android.os.Parcel;

import android.os.Parcelable;

import android.util.AttributeSet;

import android.view.View;

import android.widget.ProgressBar;

/**

* 水波圆

*

* @author lgl

*

*/

public class CircleView extends View {

private Context mContext;

private int mScreenWidth;

private int mScreenHeight;

private Paint mRingPaint;

private Paint mCirclePaint;

private Paint mWavePaint;

private Paint linePaint;

private Paint flowPaint;

private Paint leftPaint;

private int mRingSTROKEWidth = 15;

private int mCircleSTROKEWidth = 2;

private int mLineSTROKEWidth = 1;

private int mCircleColor = Color.WHITE;

private int mRingColor = Color.WHITE;

private int mWaveColor = Color.WHITE;

private Handler mHandler;

private long c = 0L;

private boolean mStarted = false;

private final float f = 0.033F;

private int mAlpha = 50;// 透明度

private float mAmplitude = 10.0F; // 振幅

private float mWaterLevel = 0.5F;// 水高(0~1)

private Path mPath;

// 绘制文字显示在圆形中间,只是我没有设置,我觉得写在布局上也挺好的

private String flowNum = "";

private String flowLeft = "还剩余";

/**

* @param context

*/

public CircleView(Context context) {

super(context);

// TODO Auto-generated constructor stub

mContext = context;

init(mContext);

}

/**

* @param context

* @param attrs

*/

public CircleView(Context context, AttributeSet attrs) {

super(context, attrs);

// TODO Auto-generated constructor stub

mContext = context;

init(mContext);

}

/**

* @param context

* @param attrs

* @param defStyleAttr

*/

public CircleView(Context context, AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

// TODO Auto-generated constructor stub

mContext = context;

init(mContext);

}

public void setmWaterLevel(float mWaterLevel) {

this.mWaterLevel = mWaterLevel;

}

private void init(Context context) {

mRingPaint = new Paint();

mRingPaint.setColor(mRingColor);

mRingPaint.setAlpha(50);

mRingPaint.setStyle(Paint.Style.STROKE);

mRingPaint.setAntiAlias(true);

mRingPaint.setStrokeWidth(mRingSTROKEWidth);

mCirclePaint = new Paint();

mCirclePaint.setColor(mCircleColor);

mCirclePaint.setStyle(Paint.Style.STROKE);

mCirclePaint.setAntiAlias(true);

mCirclePaint.setStrokeWidth(mCircleSTROKEWidth);

linePaint = new Paint();

linePaint.setColor(mCircleColor);

linePaint.setStyle(Paint.Style.STROKE);

linePaint.setAntiAlias(true);

linePaint.setStrokeWidth(mLineSTROKEWidth);

flowPaint = new Paint();

flowPaint.setColor(mCircleColor);

flowPaint.setStyle(Paint.Style.FILL);

flowPaint.setAntiAlias(true);

flowPaint.setTextSize(36);

leftPaint = new Paint();

leftPaint.setColor(mCircleColor);

leftPaint.setStyle(Paint.Style.FILL);

leftPaint.setAntiAlias(true);

leftPaint.setTextSize(36);

mWavePaint = new Paint();

mWavePaint.setStrokeWidth(1.0F);

mWavePaint.setColor(mWaveColor);

mWavePaint.setAlpha(mAlpha);

mPath = new Path();

mHandler = new Handler() {

@Override

public void handleMessage(android.os.Message msg) {

if (msg.what == 0) {

invalidate();

if (mStarted) {

// 不断发消息给自己,使自己不断被重绘

mHandler.sendEmptyMessageDelayed(0, 60L);

}

}

}

};

}

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

int width = measure(widthMeasureSpec, true);

int height = measure(heightMeasureSpec, false);

if (width < height) {

setMeasuredDimension(width, width);

} else {

setMeasuredDimension(height, height);

}

}

/**

* @category 测量

* @param measureSpec

* @param isWidth

* @return

*/

private int measure(int measureSpec, boolean isWidth) {

int result;

int mode = MeasureSpec.getMode(measureSpec);

int size = MeasureSpec.getSize(measureSpec);

int padding = isWidth ? getPaddingLeft() + getPaddingRight()

: getPaddingTop() + getPaddingBottom();

if (mode == MeasureSpec.EXACTLY) {

result = size;

} else {

result = isWidth ? getSuggestedMinimumWidth()

: getSuggestedMinimumHeight();

result += padding;

if (mode == MeasureSpec.AT_MOST) {

if (isWidth) {

result = Math.max(result, size);

} else {

result = Math.min(result, size);

}

}

}

return result;

}

@Override

protected void onSizeChanged(int w, int h, int oldw, int oldh) {

// TODO Auto-generated method stub

super.onSizeChanged(w, h, oldw, oldh);

mScreenWidth = w;

mScreenHeight = h;

}

@Override

protected void onDraw(Canvas canvas) {

// TODO Auto-generated method stub

super.onDraw(canvas);

// 得到控件的宽高

int width = getWidth();

int height = getHeight();

setBackgroundColor(mContext.getResources().getColor(R.color.main_bg));

// 计算当前油量线和水平中线的距离

float centerOffset = Math.abs(mScreenWidth / 2 * mWaterLevel

- mScreenWidth / 4);

// 计算油量线和与水平中线的角度

float horiAngle = (float) (Math.asin(centerOffset / (mScreenWidth / 4)) * 180 / Math.PI);

// 扇形的起始角度和扫过角度

float startAngle, sweepAngle;

if (mWaterLevel > 0.5F) {

startAngle = 360F - horiAngle;

sweepAngle = 180F + 2 * horiAngle;

} else {

startAngle = horiAngle;

sweepAngle = 180F - 2 * horiAngle;

}

canvas.drawLine(mScreenWidth * 3 / 8, mScreenHeight * 5 / 8,

mScreenWidth * 5 / 8, mScreenHeight * 5 / 8, linePaint);

float num = flowPaint.measureText(flowNum);

canvas.drawText(flowNum, mScreenWidth * 4 / 8 - num / 2,

mScreenHeight * 4 / 8, flowPaint);

float left = leftPaint.measureText(flowLeft);

canvas.drawText(flowLeft, mScreenWidth * 4 / 8 - left / 2,

mScreenHeight * 3 / 8, leftPaint);

// 如果未开始(未调用startWave方法),绘制一个扇形

if ((!mStarted) || (mScreenWidth == 0) || (mScreenHeight == 0)) {

// 绘制,即水面静止时的高度

RectF oval = new RectF(mScreenWidth / 4, mScreenHeight / 4,

mScreenWidth * 3 / 4, mScreenHeight * 3 / 4);

canvas.drawArc(oval, startAngle, sweepAngle, false, mWavePaint);

return;

}

// 绘制,即水面静止时的高度

// 绘制,即水面静止时的高度

RectF oval = new RectF(mScreenWidth / 4, mScreenHeight / 4,

mScreenWidth * 3 / 4, mScreenHeight * 3 / 4);

canvas.drawArc(oval, startAngle, sweepAngle, false, mWavePaint);

if (this.c >= 8388607L) {

this.c = 0L;

}

// 每次onDraw时c都会自增

c = (1L + c);

float f1 = mScreenHeight * (1.0F - (0.25F + mWaterLevel / 2))

- mAmplitude;

// 当前油量线的长度

float waveWidth = (float) Math.sqrt(mScreenWidth * mScreenWidth / 16

- centerOffset * centerOffset);

// 与圆半径的偏移量

float offsetWidth = mScreenWidth / 4 - waveWidth;

int top = (int) (f1 + mAmplitude);

mPath.reset();

// 起始振动X坐标,结束振动X坐标

int startX, endX;

if (mWaterLevel > 0.50F) {

startX = (int) (mScreenWidth / 4 + offsetWidth);

endX = (int) (mScreenWidth / 2 + mScreenWidth / 4 - offsetWidth);

} else {

startX = (int) (mScreenWidth / 4 + offsetWidth - mAmplitude);

endX = (int) (mScreenWidth / 2 + mScreenWidth / 4 - offsetWidth + mAmplitude);

}

// 波浪效果

while (startX < endX) {

int startY = (int) (f1 - mAmplitude

* Math.sin(Math.PI

* (2.0F * (startX + this.c * width * this.f))

/ width));

canvas.drawLine(startX, startY, startX, top, mWavePaint);

startX++;

}

canvas.drawCircle(mScreenWidth / 2, mScreenHeight / 2, mScreenWidth / 4

+ mRingSTROKEWidth / 2, mRingPaint);

canvas.drawCircle(mScreenWidth / 2, mScreenHeight / 2,

mScreenWidth / 4, mCirclePaint);

canvas.restore();

}

@Override

public Parcelable onSaveInstanceState() {

Parcelable superState = super.onSaveInstanceState();

SavedState ss = new SavedState(superState);

ss.progress = (int) c;

return ss;

}

@Override

public void onRestoreInstanceState(Parcelable state) {

SavedState ss = (SavedState) state;

super.onRestoreInstanceState(ss.getSuperState());

c = ss.progress;

}

@Override

protected void onAttachedToWindow() {

super.onAttachedToWindow();

// 关闭硬件加速,防止异常unsupported operation exception

this.setLayerType(View.LAYER_TYPE_SOFTWARE, null);

}

@Override

protected void onDetachedFromWindow() {

super.onDetachedFromWindow();

}

/**

* @category 开始波动

*/

public void startWave() {

if (!mStarted) {

this.c = 0L;

mStarted = true;

this.mHandler.sendEmptyMessage(0);

}

}

/**

* @category 停止波动

*/

public void stopWave() {

if (mStarted) {

this.c = 0L;

mStarted = false;

this.mHandler.removeMessages(0);

}

}

/**

* @category 保存状态

*/

static class SavedState extends BaseSavedState {

int progress;

/**

* Constructor called from {@link ProgressBar#onSaveInstanceState()}

*/

SavedState(Parcelable superState) {

super(superState);

}

/**

* Constructor called from {@link #CREATOR}

*/

private SavedState(Parcel in) {

super(in);

progress = in.readInt();

}

@Override

public void writeToParcel(Parcel out, int flags) {

super.writeToParcel(out, flags);

out.writeInt(progress);

}

public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {

public SavedState createFromParcel(Parcel in) {

return new SavedState(in);

}

public SavedState[] newArray(int size) {

return new SavedState[size];

}

};

}

}

我们运行一下

3c61b1aa29414e3f9c6e80d840a71e3d

其实他是十分的空旷的,所以也值得我们去定制,我们在中间加个流量显示,再加个进度条

activity_main.xml

xmlns:tools="http://schemas.android.com/tools"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:background="@color/main_bg" >

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_alignParentTop="true"

android:layout_centerHorizontal="true"

android:layout_marginTop="10dp"

android:text="流量"

android:textColor="@android:color/white"

android:textSize="18sp" />

android:id="@+id/wave_view"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:layout_centerInParent="true" />

android:id="@+id/power"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_centerInParent="true"

android:textColor="@android:color/white" />

android:id="@+id/seekBar"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:layout_alignParentBottom="true"

android:layout_marginBottom="150dp" />

```

>我们要实现这个,就要调用它的初始化以及start方法

```

mCircleView = (CircleView) findViewById(R.id.wave_view);

// 设置多高,float,0.1-1F

mCircleView.setmWaterLevel(0.1F);

// 开始执行

mCircleView.startWave();

别忘了activity销毁的时候把它回收哦

@Override

protected void onDestroy() {

// TODO Auto-generated method stub

mCircleView.stopWave();

mCircleView = null;

super.onDestroy();

}

我们再运行一遍

27a3e6fbd0ed4f2bacd7980f9b910ea3

但是我们要怎么让水波纹随着进度条一起上升下降尼?,这里我们就要用到我们刚才写的SeekBar了,我们实现它的setOnSeekBarChangeListener来监听,这样我们就要复写他的三个方法,这里我们只要用到一个

public void onProgressChanged(SeekBar seekBar, int progress,

boolean fromUser) {

//跟随进度条滚动

mCircleView.setmWaterLevel((float) progress / 100);

}

这里,我们要这样算的,我们设置高度的单位是float,也就是从0-1F,而我们的进度是int progress,从0-100,我们就要用(float) progress / 100)并且强转来得到单位,好了,我们现在水波纹的高度就是随着我们的进度条一起变化了,我们再来运行一下

1c17648986f8405e862d72c9e1ad81dd

好的,这样的话,我们就只剩下一个了,就是让大小随着我们的进度条变化了,这里我们因为更新UI不能再主线程中操作,所以我们需要用到我们的老伙计Handler了,但是用到handler还不够,我们的进度条数值也是在内部类里面,所以这里我们需要用到Handler来传值了,这里我们用的是Bundle,我们还是在onProgressChanged方法中操作了

//创建一个消息

Message message = new Message();

Bundle bundle = new Bundle();

//put一个int值

bundle.putInt("progress

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/409815.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[html] iframe父页面如何获取子页面的元素?

[html] iframe父页面如何获取子页面的元素&#xff1f; 在父页面监听 onmessage&#xff0c;子页面 postMessage。$(iframe)[0].contentWindow.document.getElementByIddocument.frames[xx].document.getElementById个人简介 我是歌谣&#xff0c;欢迎和大家一起交流前后端知识…

怎么更换WIN7欢迎界面的背景图?

第一步&#xff1a;先单击“开端 →运转 ”&#xff0c;打开“运转 ”对话框并输入 “Regedit”&#xff08;不包含外侧引号&#xff09;&#xff1b;接着单击“确定”按钮打开注册表编辑器&#xff0c;再定位到“HKEY_LOCAL_MACHINESOFTWARE\Microsoft\Windows\CurrentVersion…

docker php composer 使用_如何使用Docker部署PHP开发环境

本文主要介绍了如何使用Docker构建PHP的开发环境&#xff0c;文中作者也探讨了构建基于Docker的开发环境应该使用单容器还是多容器&#xff0c;各有什么利弊。推荐PHP开发者阅读。希望对大家有所帮助。环境部署一直是一个很大的问题&#xff0c;无论是开发环境还是生产环境&…

1-docker安装

一、看官方地址选择平台&#xff0c;我的是centos7 系统 https://docs.docker.com/install/linux/docker-ce/centos/二、安装依赖 sudo yum install -y yum-utils device-mapper-persistent-data lvm2三、添加软件仓库&#xff0c;我们这⾥使⽤稳定版 Docker&#xff0c;执⾏下…

from 下拉框多个值提交_Git提交规范

规范的作用大多数情况下&#xff0c;看提交历史的人跟提交代码的人都不是同一个人&#xff0c;当别人阅读你的提交历史时&#xff0c;他很可能是不知道具体代码细节的&#xff0c;你如何在最短的时间内让他一眼知道每次提交的意义&#xff1a;每次提交影响的具体范围&#xff1…

[html] 给内联元素加float与给块元素加float有什么区别?

[html] 给内联元素加float与给块元素加float有什么区别&#xff1f; 内联元素加float无效个人简介 我是歌谣&#xff0c;欢迎和大家一起交流前后端知识。放弃很容易&#xff0c; 但坚持一定很酷。欢迎大家一起讨论 主目录 与歌谣一起通关前端面试题

PHP---反射

所谓反射就是定义好一个类之后&#xff0c;通过ReflectionClass读取类的名字从而获取类结构信息的过程class mycoach {protected $name;protected $age;public function __construct($name,$age){$this->name $name;$this->age $age;}public function eat(){echo "…

python词云_python词云

python词云[编辑] 概述 python词云是一种构建词云的方法&#xff0c;利用通用的编程语言Python来做词云&#xff0c;虽然不如专用工具便捷&#xff0c;但是适用范围很广&#xff0c;满足了不同人对词云的个性化需求。 一.Python的介绍 Python是一种面向对象的解释型计算机程序设…

【物联网智能网关-03】GPRS模块中文短信收发

在去年年初&#xff0c;就已经推出V1.0.0的GPRS库&#xff0c;不过在这个版本上只是实现了西文短信收发和字符串方式的GPRS数据通信&#xff0c;功能还相对不完善&#xff08;参见我以前的博文《GPRS通信实现》&#xff09;。最近升级的版本&#xff0c;对以上功能进行了大幅度…

[html] html的img标签为什么要添加alt属性呢?

[html] html的img标签为什么要添加alt属性呢&#xff1f; alt 属性是一个必需的属性&#xff0c;它规定在图像无法显示时的替代文本。假设由于一些原因&#xff0c;用户无法查看图像&#xff0c;alt属性可以为图像提供替代的信息。比如&#xff1a;网速太慢src 属性中的错误浏…

蓄电池单格电压多少伏_蓄电池充电规范手册

很多用户在买完蓄电池之后第一想法就是赶紧充电&#xff0c;很多陋习让用户使用行为造成了新买的蓄电池没怎么用感觉就和旧的没啥区别。而且使用时间越来越短到头来企业还失去了很多的客户&#xff0c;德国阳光蓄电池手册整理整编了在不同的环境中我们该如何很好的去维护自己的…

1-1docker加速器

配置加速器 #编译配置 sudo vim /etc/docker/daemon.json#加入下面的数据{"registry-mirrors": ["https://docker.mirrors.aliyuncs.com"] }#阿里云的镜像&#xff1a; https://docker.mirrors.aliyuncs.com#docker-cn镜像&#xff1a;https://registry.do…

钉钉机器人关键词应答_除了用于电销,智能语音机器人可以应用哪些地方?

之前的文章探讨的是智能语音机器人在电销行业的应用&#xff0c;然而在实际的场景中&#xff0c;电销行业的应用只是大家所熟知的行业之一。对比于人工电销&#xff0c;使用智能语音机器人有着诸多优势&#xff0c;例如&#xff1a;工作效率高、意向筛选、电话录音并转化为文字…

[html] 举例说明实现文字贯穿线的方法有哪些?

[html] 举例说明实现文字贯穿线的方法有哪些&#xff1f; 就是这样吗&#xff0c;用 del 删除线 <del></del>个人简介 我是歌谣&#xff0c;欢迎和大家一起交流前后端知识。放弃很容易&#xff0c; 但坚持一定很酷。欢迎大家一起讨论 主目录 与歌谣一起通关前端…

python+html语音人物交互_将HTML输入传递到python脚本

我有一个Python脚本&#xff0c;我想创建一个非常简单的HTML表单&#xff0c;有3个字段(用户名、密码和ID)和一个submit按钮。在当我单击Submit时&#xff0c;我只想将这三个参数传递到Python脚本中并运行脚本。在我试着用CGI来做。我创建了一个cgi-bin文件夹&#xff0c;并在其…

1-2docker-基本的使用

1、Docker 官⽅提供了⼀个公共的镜像仓库 https://hub.docker.com2、获取镜像 docker pull [选项] [Docker Registry 地址[:端⼝]/]仓库名[:标签]3、运行镜像 docker run -it --rm ubuntu:16.04 /bin/bash -it&#xff1a;这是两个参数&#xff0c;⼀个是 -i&#xff1a;交互式…

[html] 说说你对html的嵌套规范的理解,都有哪些规范呢?

[html] 说说你对html的嵌套规范的理解&#xff0c;都有哪些规范呢&#xff1f; ul,li/ol,li/dl,dt,dd拥有父子级关系的标签&#xff1b;ul、ol下都只能跟li&#xff0c;dl下只能跟dt.dd。 p,dt,h标签里面不能嵌套块元素&#xff1b; a标签不能嵌套a&#xff1b; 行内元素不能嵌…

assert函数_PHP 之 assert()函数

assert()函数其实是一个断言函数。那么什么是断言呢&#xff1f;百度百科上是这么说的&#xff1a;编写代码时&#xff0c;我们总是会做出一些假设&#xff0c;断言就是用于在代码中捕捉这些假设。说到这里&#xff0c;大家应该能知道assert()函数是干嘛用的了吧&#xff1f;好…

android 同根动画_android 动画系列 (1) - tween 动画(view动画)

这是我这个系列的目录&#xff0c;有兴趣的可以看下&#xff1a; android 动画系列 - 目录tween 动画早些时候我们也叫补间动画(我也不知道为啥),现在也有叫 view 动画的。tween动画是2.X 时代的产物&#xff0c;因为效果不理想&#xff0c;4.X 时代推出了动画的升级版 属性动画…

1-3docker commit定制镜像

以定制⼀个 Web 服务器为例⼦1、commit定制镜像 docker pull nginx:1.17运行容器 --name:容器名字 -d&#xff1a;后台 -p本地端口&#xff1a;容器内端口 docker run --name webserver -d -p 8080:80 nginx:1.17#进入容器 docker exec -it webserver /bin/bash#进入容器执…