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

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];

}

};

}

}

我们运行一下

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

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();

}

我们再运行一遍

但是我们要怎么让水波纹随着进度条一起上升下降尼?,这里我们就要用到我们刚才写的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)并且强转来得到单位,好了,我们现在水波纹的高度就是随着我们的进度条一起变化了,我们再来运行一下

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

//创建一个消息

Message message = new Message();

Bundle bundle = new Bundle();

//put一个int值

bundle.putInt("progress

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

  1. Android 之自定义view实现水波纹效果

    在实际的开发中,很多时候还会遇到相对比较复杂的需求,比如产品妹纸或UI妹纸在哪看了个让人兴奋的效果,兴致高昂的来找你,看了之后目的很明确,当然就是希望你能给她: 在这样的关键时候,身子板就一定得硬了, ...

  2. android水波纹点击动画,android 控件点击水波纹效果的几种方案

    目前我所知道的至少有三种可以实现点击水波纹的效果 第一种:安卓自带的方法 在安卓中有自带的一种属性,可以实现水波纹的效果,就是在所需要点击的控件属性加上如下代码: android:background ...

  3. android水波效果,android动态壁纸中的水波纹效果

    [实例简介] android动态壁纸中的水波纹效果,采用opengl中的shader实现 [实例截图] [核心代码] @Override public String getVertexShader() ...

  4. 高端大气仿A8源码素材下载站源码+基于织梦CMS

    正文: 高端大气仿A8源码素材下载站源码+基于织梦CMS,这源码的前端UI看着还是非常不错的,高端大气响应式,且程序亲测没有问题,下载,发布,支付,都是正常的. 安装教程: 程序: lanzou.co ...

  5. Android之旅:仿魅族应用商店下载进度控件

    前言 实现过程 需求分析 具体动手 定义需要的参数 重写onDraw() 属性动画 设置文字 自定义属性 暴露更新进度的方法供外界调用: 使用方法: 问题 前言 因为本人是个魅族控,魅族的UI以及页面 ...

  6. Android S 指纹解锁后的水波纹动画

    记录一下bug 由于测试人员对比了R和S的行为,还有Google Pixel6的行为都没有指纹解锁后的蓝色水波纹动画,所以寻找了好久才发现在Android S的SystemUI上多了一个类-AuthR ...

  7. OC 5266 降压型恒流驱动器,ESOP8 封装,高端电流检测

    概述 OC5266 是内置功率 MOS,同时可支 持外扩驱动 NMOS 的一款连续电感电流 导通模式的降压型 LED 恒流驱动器,用于 驱动一个或多个 LED 灯串. OC5266 工作 电压从 5. ...

  8. android 辐射动画_Android仿微信雷达辐射搜索好友(逻辑清晰实现简单)

    不知不觉这个春节也已经过完了,遗憾家里没网,没能及时给大家送上祝福,今天回到深圳,明天就要上班了,小伙伴们是不是和我一样呢?今天讲的是一个大家都见过的动画,雷达搜索好友嘛,原理也十分的简单,你看完我的 ...

  9. Android案例手册 - 定位点圆形水波纹和椭圆水波纹

    往期文章分享 点击跳转=><导航贴>- Unity手册,系统实战学习 点击跳转=><导航贴>- Android手册,重温移动开发 本文约18千字,新手阅读需要18分 ...

最新文章

  1. hadoop中HBase子项目入门讲解
  2. Java读写文件,中文乱码解决
  3. 查看mysql日志文件大小和数据库大小
  4. Android OpenCV Manager简介
  5. Django常用的模块
  6. jQuery progression 表单进度
  7. 如何写一个bat批处理自动上传文件到FTP
  8. 假设以带头结点的循环链表表示队列_JavaScript数据结构之链表--设计
  9. 算法导论4--求最大和数组
  10. docker 容器 exited_docker常用命令整理
  11. Linux 一句话 命令
  12. [题解]Shorten IPv6 Address-模拟(2019牛客多校第六场B题)
  13. java 读取wav采样数据_读取wav文件中的音频数据操作
  14. TMDB数据导入elasticsearch7
  15. android 4.4 root精灵,ROOT精灵: 支持安卓4.3/4.4机型一键ROOT
  16. 浙江移动无线dns服务器地址,首选dns_浙江省宁波市(中国移动)首选dns是什么,备选dns是什么...
  17. 下行期的资本,正在追逐「猫品牌」
  18. WannaCry笔记
  19. 中国工商银行网上银行B2C在线支付接口说明
  20. 网络收敛是什么意思_收敛是什么意思(什么是收敛性)

热门文章

  1. js 数组遍历符合条件跳出循环体_C++模拟面试:从数组“紧凑”操作说开来
  2. python中add_Python add()函数是如何使用呢?
  3. ajax拼接显示不同样式,Ajax重点整理
  4. 家里wifi网速越来越慢_家里的wifi信号不好?有了它再也不怕网速慢啦
  5. mysql 5.0 数据库_mysql5.0常用命令
  6. ubuntu下搭建tftp服务器
  7. O_RDWR, O_CREAT等open函数标志位在哪里定义?
  8. 前端学习(3183):ant-design的button介绍按钮属性
  9. [vue] ajax、fetch、axios这三都有什么区别?
  10. 前端学习(2883):实现事件处理函数批量绑定