我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Android自定义WaveView实现波浪进度效果

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Android自定义WaveView实现波浪进度效果

实现原理

首先就是自定义个WaveView 继承View,然后再WaveView 内部实现代码逻辑:

      ① 水波就波嘛? sin函数? 贝塞尔曲线? 都行,这里就用二阶贝塞 尔曲线去画吧

      ② 波要动嘛,怎么动呢?线程? 好吧 这里用了个Handler。

      ③绘制波首先要找点,那么在

onMeasure()
里找出需要的点咯,这里就暂时展示一个波段吧,一个波长移动左边不就没了?OK 那就两个波吧,吼吼,两个波(猥琐男潜质表露无遗啊)。接下来就是Handler 结合
onDraw()
绘制。OK,那就先看我Word绘制的粗瘪的波动图,请看VCR,oh,no... gif

意思就是波平移一个波长之后回到初始位置继续平移循环。

好吧,有人说了,这么简单的逻辑你要啰嗦那么多???

好吧,我承认,我有唐僧的潜质。。。

闲话就不说了,先上

效果图


示例代码如下

调用的Activity


 * Created by LiuDong on 2016/12/22.
 * Email:15002102128@126.com
 */
public class WaveActivity extends Activity {
 LD_WaveView waveView;//方形
 LD_WaveView waveCircleView;//圆形
 private int progrees=0;//进度
 private Handler mHandler=new Handler(){
  @Override
  public void handleMessage(Message msg) {
   if (progrees==100) progrees=0;
   Log.i("progress",progrees+"");
   waveView.setmProgress(progrees++);
   waveCircleView.setmProgress(progrees++);
   mHandler.sendEmptyMessageDelayed(0,100);
  }
 };
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_wave);
  waveView= (LD_WaveView) findViewById(R.id.waveView);
  waveCircleView= (LD_WaveView) findViewById(R.id.waveViewCircle);
  mHandler.sendEmptyMessageDelayed(0,10);
 }
}

xml布局


<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:app="http://schemas.android.com/apk/res-auto"
 android:orientation="vertical" android:layout_width="match_parent"
 android:background="@color/ld_White"
 android:layout_height="match_parent">
 <com.dadong.ld_tools.widget.LD_WaveView
  android:id="@+id/waveViewCircle"
  android:layout_marginTop="20dp"
  android:layout_width="100dp"
  android:layout_centerHorizontal="true"
  android:layout_height="100dp"
  app:wave_color="@color/ld_Black"
  app:wave_circle="true"
  />
 <com.dadong.ld_tools.widget.LD_WaveView
  android:id="@+id/waveView"
  android:layout_width="100dp"
  android:layout_height="100dp"
  app:wave_color="@color/ld_Black"
  app:wave_circle="false"
  android:layout_centerInParent="true" />
</RelativeLayout>

自定义WaveView



public class LD_WaveView extends View {
 private int mProgress;//进度
 private int mTimeStep = 10;//时间间隔
 private int mSpeed = 5;//波单次移动的距离
 private int mViewHeight;//视图宽高
 private int mViewWidth;//视图宽度
 private int mLevelLine;// 基准线
 private int mWaveLength;//波长 暂定view宽度为一个波长
 private int mStrokeWidth;//园的线宽
 private RectF rectF;//圆环区域
 private int mWaveHeight;//波峰高度
 private int mLeftWaveMoveLength;//波平移的距离,用来控制波的起点位置
 private int mWaveColor;//波的颜色
 private Paint mPaint;//画笔
 private Paint mCirclePaint;//圆环画笔
 private Paint mBorderPaint;//边界画笔
 private int mBorderWidth=4;//边界宽度
 private Paint mTextPaint;//文字画笔
 private Path mPath;//绘画线
 private List<Point> mPoints;//点的集合
 private boolean isMeasure = false;//是否已测量过
 private boolean isCircle=false;//是否圆形默认false,可属性代码设置
 //处理消息
 private Handler handler = new Handler() {
  @Override
  public void handleMessage(Message msg) {
   initWaveMove();
  }
 };
 
 private void initWaveMove(){
  mLeftWaveMoveLength+=mSpeed;//波向右移动距离增加mSpeed;
  if (mLeftWaveMoveLength>=mWaveLength){//当增加到一个波长时回复到0
   mLeftWaveMoveLength=0;
  }
  invalidate();
 }
 public LD_WaveView(Context context) {
  this(context, null);
 }
 public LD_WaveView(Context context, AttributeSet attrs) {
  this(context, attrs, 0);
 }
 public LD_WaveView(Context context, AttributeSet attrs, int defStyleAttr) {
  super(context, attrs, defStyleAttr);
  getAttr(context, attrs, defStyleAttr);
  init();
 }
 
 private void init() {
  mPoints = new ArrayList<Point>();
  //波浪轨迹画笔
  mPaint = new Paint();
  mPaint.setAntiAlias(true);
  mPaint.setColor(mWaveColor);
  mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
  mPath = new Path();
  //文字画笔
  mTextPaint=new Paint();
  mTextPaint.setColor(Color.RED);
  mTextPaint.setTextAlign(Paint.Align.CENTER);
  mTextPaint.setTextSize(48);
  //圆环画笔
  mCirclePaint=new Paint();
  mCirclePaint.setAntiAlias(true);
  mCirclePaint.setColor(Color.WHITE);
  mCirclePaint.setStyle(Paint.Style.STROKE);
  //边界线画笔
  mBorderPaint=new Paint();
  mBorderPaint.setAntiAlias(true);
  mBorderPaint.setColor(mWaveColor);
  mBorderPaint.setStrokeWidth(mBorderWidth);
  mBorderPaint.setStyle(Paint.Style.STROKE);
 }
 
 private void getAttr(Context context, AttributeSet attrs, int defStyle) {
  TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.LD_WaveView, defStyle, 0);
  mWaveColor = a.getColor(R.styleable.LD_WaveView_wave_color, Color.RED);
  isCircle=a.getBoolean(R.styleable.LD_WaveView_wave_circle,false);
  a.recycle();
 }
 
 @Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  if (!isMeasure&&Math.abs(getMeasuredHeight()-getMeasuredWidth())<50) {//只计算一次就够了 ,relativelayout的时候要绘制两次 加个宽高判断
   mViewHeight = getMeasuredHeight();
   mViewWidth = getMeasuredWidth();
   mLevelLine = mViewHeight; //初始化波的准位线  起始位视图最底部
   {
    mLevelLine = mViewHeight * (100-mProgress) / 100;
    if (mLevelLine < 0) mLevelLine = 0;
   }
   //计算波峰值
   mWaveHeight = mViewHeight / 20;//波峰暂定为view高度的1/20,如果需要设置 可设置set方法赋值;
   mWaveLength = getMeasuredWidth();
   //计算所有的点 这里取宽度为整个波长 往左再延伸一个波长 两个波长则需要9个点
   for (int i = 0; i < 9; i++) {
    int y = 0;
    switch (i % 4) {
     case 0:
      y = mViewHeight;
      break;
     case 1:
      y =mViewHeight+ mWaveHeight;
      break;
     case 2:
      y = mViewHeight;
      break;
     case 3:
      y = mViewHeight-mWaveHeight;
      break;
    }
    Point point = new Point(-mWaveLength + i * mWaveLength / 4, y);
    mPoints.add(point);
   }
   
   int mIncircleRadius=mViewHeight<mViewWidth?mViewHeight/2:mViewWidth/2;//内切圆半径
   int mcircumcircleRadius= (int) (Math.sqrt((float)(Math.pow(mViewHeight/2,2)+Math.pow(mViewWidth/2,2)))+0.5);//外接圆半径
   int radius=mcircumcircleRadius/2+mIncircleRadius/2;
   rectF=new RectF(mViewWidth/2-radius,mViewHeight/2-radius,mViewWidth/2+radius,mViewHeight/2+radius);
   mStrokeWidth=mcircumcircleRadius-mIncircleRadius;
   mCirclePaint.setStrokeWidth(mStrokeWidth);//线是有宽度的 采用了这种方式画圆环
   isMeasure = true;
  }
 }
 @Override
 protected void onDraw(Canvas canvas) {
  super.onDraw(canvas);
  
  mPath.reset();
  int i = 0;
  mPath.moveTo(mPoints.get(0).getX()+mLeftWaveMoveLength, mPoints.get(0).getY()-mViewHeight*mProgress/100);
  for (; i < mPoints.size() - 2; i += 2) {
   mPath.quadTo(mPoints.get(i + 1).getX()+mLeftWaveMoveLength, mPoints.get(i + 1).getY()-mViewHeight*mProgress/100, mPoints.get(i + 2).getX()+mLeftWaveMoveLength, mPoints.get(i + 2).getY()-mViewHeight*mProgress/100);
  }
  mPath.lineTo(mPoints.get(i).getX()+mLeftWaveMoveLength, mViewHeight);
  mPath.lineTo(mPoints.get(0).getX()+mLeftWaveMoveLength, mViewHeight);
  mPath.close();
  
  canvas.drawPath(mPath,mPaint);
  Rect rect = new Rect();
  String progress=String.format("%d%%",mProgress);
  mTextPaint.getTextBounds(progress,0,progress.length(), rect);
  int textHeight = rect.height();
  if (mProgress>=50)//如果进度达到50 颜色变为白色,没办法啊,进度在中间 不变颜色看不到
   mTextPaint.setColor(Color.WHITE);
  else
  mTextPaint.setColor(mWaveColor);
  canvas.drawText(progress,0,progress.length(),mViewWidth/2,mViewHeight/2+textHeight/2,mTextPaint);
  if (isCircle) {
   
   canvas.drawArc(rectF, 0, 360, true, mCirclePaint);
   Paint circlePaint = new Paint();
   circlePaint.setStrokeWidth(5);
   circlePaint.setColor(Color.WHITE);
   circlePaint.setAntiAlias(true);
   circlePaint.setStyle(Paint.Style.STROKE);
   canvas.drawCircle(mViewWidth / 2, mViewHeight / 2, mViewHeight / 2, circlePaint);
   
   mBorderPaint.setStrokeWidth(mBorderWidth/2);
  canvas.drawCircle(mViewWidth/2,mViewHeight/2,mViewHeight/2-mBorderWidth/2,mBorderPaint);
  }else {
   
   canvas.drawRect(0,0,mViewWidth,mViewHeight,mBorderPaint);
  }
  //
  handler.sendEmptyMessageDelayed(0,mTimeStep);
 }
 
 public void setmProgress(int mProgress) {
  this.mProgress = mProgress;
  mLevelLine=(100-mProgress)*mViewHeight/100;
 }
 
 public void setCircle(boolean circle) {
  isCircle = circle;
 }
}

自定义属性


<?xml version="1.0" encoding="utf-8"?>
<resources>
 <declare-styleable name="LD_WaveView">
  <attr name="wave_color" format="color"></attr>
  <attr name="wave_circle" format="boolean"></attr>
 </declare-styleable>
</resources>

总结

好了,以上就是这篇文章的全部内容了,代码里备注应该还算比较清楚了,希望能对一些人有一些帮助,瑕疵不足之处欢迎指正,或者有好的建议。也可以留言交流。

您可能感兴趣的文章:Android中实现Webview顶部带进度条的方法android自定义进度条渐变色View的实例代码android ListView和ProgressBar(进度条控件)的使用方法Android自定义View实现带数字的进度条实例代码Android Webview添加网页加载进度条实例详解Android 自定义view和属性动画实现充电进度条效果Android view自定义实现动态进度条Android自定义View基础开发之图片加载进度条Android自定义view实现水波纹进度球效果Android自定义View实现圆弧进度效果


免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Android自定义WaveView实现波浪进度效果

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Android自定义WaveView实现波浪进度效果

实现原理 首先就是自定义个WaveView 继承View,然后再WaveView 内部实现代码逻辑: ① 水波就波嘛? sin函数? 贝塞尔曲线? 都行,这里就用二阶贝塞 尔曲线去画吧 ② 波要动嘛,怎么动呢?线程?
2022-06-06

Android自定义view实现水波纹进度球效果

今天我们要实现的这个view没有太多交互性的view,所以就继承view。 自定义view的套路,套路很深 1、获取我们自定义属性attrs(可省略) 2、重写onMeasure方法,计算控件的宽和高 3、重
2022-06-06

Android WaveView实现水流波动效果

水流波动的波形都是三角波,曲线是正余弦曲线,但是Android中没有提供绘制正余弦曲线的API,好在Path类有个绘制贝塞尔曲线的方法quadTo,绘制出来的是2阶的贝塞尔曲线,要想实现波动效果,只能用它来绘制Path曲线。待会儿再讲
2022-06-06

Android编程使用自定义View实现水波进度效果示例

本文实例讲述了Android编程使用自定义View实现水波进度效果。分享给大家供大家参考,具体如下:首先上效果图:简介:1.自动适应屏幕大小;2.水波自动横向滚动;3.各种绘制参数可通过修改常量进行控制。代码不多,注释也比较详细,全部贴上:
2023-05-31

Android自定义View实现水波纹效果

介绍:水波纹散开效果的控件在 App 里面还是比较常见的,例如 网易云音乐歌曲识别,附近搜索场景。看下实现的效果:实现思路: 先将最大圆半径与最小圆半径间距分成几等份,从内到外,Paint 透明度依次递减,绘制出同心圆,然后不断的改变这些同
2023-05-30

Android自定义view实现进度条指示效果

先看看效果图:首先是布局文件
2022-06-06

如何利用CSS实现波浪进度条效果

本篇内容介绍了“如何利用CSS实现波浪进度条效果”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!CSS Painting API再简单快速的过
2023-07-04

Android自定义Material进度条效果

首先看下效果图布局文件:2022-06-06

Android实现波浪线效果(xml bitmap)

我们要实现的效果如下:在这之前先带大家了解一下xml bitmap,何为XML Bitmap? XML Bitmap 是一个用XML定义的文件放在资源目录,定义的对象是图片,为bitmap定义别名,这个文件可以给bitmap定义一些额外的属
2022-06-06

Android 自定义view实现水波纹动画效果

在实际的开发中,很多时候还会遇到相对比较复杂的需求,比如产品妹纸或UI妹纸在哪看了个让人兴奋的效果,兴致高昂的来找你,看了之后目的很明确,当然就是希望你能给她;在这样的关键时候,身子板就一定得硬了,可千万别说不行,爷们儿怎么能说不行呢;好了
2023-05-31

Android实现自定义华丽的水波纹效果

先来看看效果实现效果模拟水波纹的效果:点击屏幕就有圆环出现,半径从小到大,透明度从大到小(0为透明) 实现思路 1.自定义类继承View。 2.定义每个圆环的实体类 Wave,并初始化绘制圆环的画笔的数据。 3
2022-06-06

Android自定义View实现钟摆效果进度条PendulumView

在网上看到了一个IOS组件PendulumView,实现了钟摆的动画效果。由于原生的进度条确实是不好看,所以想可以自定义View实现这样的效果,以后也可以用于加载页面的进度条。 废话不多说,先上效果图 底部黑边是录制时不小心录上的,可以忽
2022-06-06

Android怎么自定义View实现圆弧进度效果

这篇文章主要介绍“Android怎么自定义View实现圆弧进度效果”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Android怎么自定义View实现圆弧进度效果”文章能帮助大家解决问题。技术实现1.
2023-07-06

聊聊怎么利用CSS实现波浪进度条效果

本篇文章给大家分享CSS 高阶技巧,介绍一下如何使用CSS实现波浪进度条效果,希望对大家有所帮助!
2023-05-14

编程热搜

  • Android:VolumeShaper
    VolumeShaper(支持版本改一下,minsdkversion:26,android8.0(api26)进一步学习对声音的编辑,可以让音频的声音有变化的播放 VolumeShaper.Configuration的三个参数 durati
    Android:VolumeShaper
  • Android崩溃异常捕获方法
    开发中最让人头疼的是应用突然爆炸,然后跳回到桌面。而且我们常常不知道这种状况会何时出现,在应用调试阶段还好,还可以通过调试工具的日志查看错误出现在哪里。但平时使用的时候给你闹崩溃,那你就欲哭无泪了。 那么今天主要讲一下如何去捕捉系统出现的U
    Android崩溃异常捕获方法
  • android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
    系统的设置–>电池–>使用情况中,统计的能耗的使用情况也是以power_profile.xml的value作为基础参数的1、我的手机中power_profile.xml的内容: HTC t328w代码如下:
    android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
  • Android SQLite数据库基本操作方法
    程序的最主要的功能在于对数据进行操作,通过对数据进行操作来实现某个功能。而数据库就是很重要的一个方面的,Android中内置了小巧轻便,功能却很强的一个数据库–SQLite数据库。那么就来看一下在Android程序中怎么去操作SQLite数
    Android SQLite数据库基本操作方法
  • ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
    工作的时候为了方便直接打开编辑文件,一些常用的软件或者文件我们会放在桌面,但是在ubuntu20.04下直接直接拖拽文件到桌面根本没有效果,在进入桌面后发现软件列表中的软件只能收藏到面板,无法复制到桌面使用,不知道为什么会这样,似乎并不是很
    ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
  • android获取当前手机号示例程序
    代码如下: public String getLocalNumber() { TelephonyManager tManager =
    android获取当前手机号示例程序
  • Android音视频开发(三)TextureView
    简介 TextureView与SurfaceView类似,可用于显示视频或OpenGL场景。 与SurfaceView的区别 SurfaceView不能使用变换和缩放等操作,不能叠加(Overlay)两个SurfaceView。 Textu
    Android音视频开发(三)TextureView
  • android获取屏幕高度和宽度的实现方法
    本文实例讲述了android获取屏幕高度和宽度的实现方法。分享给大家供大家参考。具体分析如下: 我们需要获取Android手机或Pad的屏幕的物理尺寸,以便于界面的设计或是其他功能的实现。下面就介绍讲一讲如何获取屏幕的物理尺寸 下面的代码即
    android获取屏幕高度和宽度的实现方法
  • Android自定义popupwindow实例代码
    先来看看效果图:一、布局
  • Android第一次实验
    一、实验原理 1.1实验目标 编程实现用户名与密码的存储与调用。 1.2实验要求 设计用户登录界面、登录成功界面、用户注册界面,用户注册时,将其用户名、密码保存到SharedPreference中,登录时输入用户名、密码,读取SharedP
    Android第一次实验

目录