android 进阶之路-自定义view-水波纹进度球

如果你是老司机,一看标题就会就return吧,嘻嘻。

在我们的日常开发中自定义控件还是用的挺多的,设计师或者产品为了更好的漂亮,美观,交互都会做一些牛逼的ui效果图,但是最后实现的还是我们程序员啊。

所以说 自定义view你还是得会的。

要开车了哦,请刷卡...

滴,老司机卡

滴,学生卡

滴,...

刷卡

今天我们要实现的这个view没有太多交互性的view,所以就继承view

自定义view的套路,套路很深

获取我们自定义属性attrs(可省略)

重写onMeasure方法,计算控件的宽和高

重写onDraw方法,绘制我们的控件

这么看来,自定义view的套路很清晰嘛。

我们看下今天的效果图,其中一个是放慢的效果(时间调的长)

效果图1

效果图2

我们按照套路来。

一.自定义属性

看下效果图我们就知道因该需要哪些属性。就不说了。

然后就是获取我们的这些属性,就是用TypedArray来获取。当然是在构造中获取,一般我们会复写构造方法,少参数调用参数多的,然后走到参数最多的那个。

下面是获取自定义属性的代码:

TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.WaveProgressView, defStyleAttr, R.style.WaveProgressViewDefault);

radius = (int) a.getDimension(R.styleable.WaveProgressView_radius, radius);

textColor = a.getColor(R.styleable.WaveProgressView_progress_text_color, 0);

textSize = a.getDimensionPixelSize(R.styleable.WaveProgressView_progress_text_size, 0);

progressColor = a.getColor(R.styleable.WaveProgressView_progress_color, 0);

radiusColor = a.getColor(R.styleable.WaveProgressView_radius_color, 0);

progress = a.getFloat(R.styleable.WaveProgressView_progress, 0);

maxProgress = a.getFloat(R.styleable.WaveProgressView_maxProgress, 100);

a.recycle();

注: R.style.WaveProgressViewDefault是这个控件的默认样式。

二.onMeasure测量

我们重写这个方法主要是根据父控件的宽和高来设置自己的宽和高。

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

//计算宽和高

int exceptW = getPaddingLeft() + getPaddingRight() + 2 * radius;

int exceptH = getPaddingTop() + getPaddingBottom() + 2 * radius;

int width = resolveSize(exceptW, widthMeasureSpec);

int height = resolveSize(exceptH, heightMeasureSpec);

int min = Math.min(width, height);

this.width = this.height = min;

//计算半径,减去padding的最小值

int minLR = Math.min(getPaddingLeft(), getPaddingRight());

int minTB = Math.min(getPaddingTop(), getPaddingBottom());

minPadding = Math.min(minLR, minTB);

radius = (min - minPadding * 2) / 2;

setMeasuredDimension(min, min);

}

首先该控件的宽和高肯定是一样的,因为是个圆嘛。其实是宽和高与半径和内边距(padding)有关,这里的内边距,我们取上下左右最小的一个。宽和高也选择取最小的。

this.width = this.height = min; 包含左右边距。

resolveSize这个方法很好的为我们实现了我们想要的宽和高我慢看下源码。

public static int resolveSizeAndState(int size, int measureSpec, int childMeasuredState) {

final int specMode = MeasureSpec.getMode(measureSpec);

final int specSize = MeasureSpec.getSize(measureSpec);

final int result;

switch (specMode) {

case MeasureSpec.AT_MOST:

if (specSize < size) {

result = specSize | MEASURED_STATE_TOO_SMALL;

} else {

result = size;

}

break;

case MeasureSpec.EXACTLY:

result = specSize;

break;

case MeasureSpec.UNSPECIFIED:

default:

result = size;

}

return result | (childMeasuredState & MEASURED_STATE_MASK);

}

如果我们自己写也是这样写。

最后通过setMeasuredDimension设置宽和高。

三.onDraw绘制

关于绘制有很多android 提供了很多API,这里就不多说了。

绘制首先就是一些画笔的初始化。

需要提一下绘制path路径的画笔设置为PorterDuff.Mode.SRC_IN模式,这个模式只显示重叠的部分。

pathPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

pathPaint.setColor(progressColor);

pathPaint.setDither(true);

pathPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));

我们要将所有的绘制 绘制到一个透明的bitmap上,然后将这个bitmap绘制到canvas上。

if (bitmap == null) {

bitmap = Bitmap.createBitmap(this.width, this.height, Bitmap.Config.ARGB_8888);

bitmapCanvas = new Canvas(bitmap);

}

为了方便计算和绘制,我将坐标系平移padding的距离

bitmapCanvas.save();

//移动坐标系

bitmapCanvas.translate(minPadding, minPadding);

// .... some thing

bitmapCanvas.restore();

3.1绘制圆

bitmapCanvas.drawCircle(radius, radius, radius, circlePaint);

3.2绘制PATH 路径.

一是要实现波纹的左右飘,和上下的振幅慢慢的减小

绘制这个之前我们需要知道二阶贝塞尔曲线的大致原理。

简单的说就是知道:P1起始点,P2是终点,P1是控制点.利用塞尔曲线的公式就可以得道沿途的一些点,最后把点连起来就是喽。

下面这个图片来于网络:

二阶贝塞尔曲线

在android-sdk里提供了绘制贝塞尔曲线的函数rQuadTo方法

public void rQuadTo(float dx1, float dy1, float dx2, float dy2)

dx1:控制点X坐标,表示相对上一个终点X坐标的位移坐标,可为负值,正值表示相加,负值表示相减;

dy1:控制点Y坐标,相对上一个终点Y坐标的位移坐标。同样可为负值,正值表示相加,负值表示相减;

dx2:终点X坐标,同样是一个相对坐标,相对上一个终点X坐标的位移值,可为负值,正值表示相加,负值表示相减;

dy2:终点Y坐标,同样是一个相对,相对上一个终点Y坐标的位移值。可为负值,正值表示相加,负值表示相减;

这四个参数都是传递的都是相对值,相对上一个终点的位移值。

要实现振幅慢慢的减小我们可以调节控制点的y坐标即可,即:

float percent=progress * 1.0f / maxProgress;

就可以得到[0,1]的

一个闭区间,[0,1]这货好啊,我喜欢,可以来做很多事情。

这样我们就可以根据percent来调节控制点的y坐标了。

//根据直径计算绘制贝赛尔曲线的次数

int count = radius * 4 / 60;

//控制-控制点y的坐标

float point = (1 - percent) * 15;

for (int i = 0; i < count; i++) {

path.rQuadTo(15, -point, 30, 0);

path.rQuadTo(15, point, 30, 0);

}

这里给出一个振幅的原理图:

振幅

然后就是根据宽来循环周期就可以了

要实现左右波纹只需要控制闭合路径的左上角的x坐标即可,当然也是根据percent喽。

大家可以结合下面这个图来理解下上面的话。

原理图

path绘制的完整代码片段。

//绘制PATH

//重置绘制路线

path.reset();

float percent=progress * 1.0f / maxProgress;

float y = (1 - percent) * radius * 2;

//移动到右上边

path.moveTo(radius * 2, y);

//移动到最右下方

path.lineTo(radius * 2, radius * 2);

//移动到最左下边

path.lineTo(0, radius * 2);

//移动到左上边

// path.lineTo(0, y);

//实现左右波动,根据progress来平移

path.lineTo(-(1 -percent) * radius*2, y);

if (progress != 0.0f) {

//根据直径计算绘制贝赛尔曲线的次数

int count = radius * 4 / 60;

//控制-控制点y的坐标

float point = (1 - percent) * 15;

for (int i = 0; i < count; i++) {

path.rQuadTo(15, -point, 30, 0);

path.rQuadTo(15, point, 30, 0);

}

}

//闭合

path.close();

bitmapCanvas.drawPath(path, pathPaint);

3.3绘制进度的文字

这个就比较简单了,绘制在控件的中间即可。关于文字的坐标计算还是很好理解的。

//绘制文字

String text = progress + "%";

float textW = textPaint.measureText(text);

Paint.FontMetrics fontMetrics = textPaint.getFontMetrics();

float baseLine = radius - (fontMetrics.ascent + fontMetrics.descent) / 2;

bitmapCanvas.drawText(text, radius - textW / 2, baseLine, textPaint);

最后别忘了把我们的bitmap绘制到canvas上。

canvas.drawBitmap(bitmap, 0, 0, null);

哦,最后是实用方法,这里我们不用thread+handler,我们用属性动画。

你懂的!!!,like

ObjectAnimator objectAnimator0 = ObjectAnimator.ofFloat(waveProgressView_0, "progress", 0f, 100f);

objectAnimator0.setDuration(3300);

objectAnimator0.setInterpolator(new LinearInterpolator());

objectAnimator0.start();

android自定义水波纹,android 自定义view-水波纹进度球相关推荐

  1. android 图片处理过程中添加进度条,『Android自定义View实战』给我一个图标,还你一个水波纹进度球...

    前言 我们都知道,平时表现进度的方式有千千万万种(没有UI想不到的,只有你做不到的= =.),其中有一种就是水波纹进度球的形式,网上很多种实现都是直接采用纯色填充的方式,即水波纹都是纯颜色填充,效果看 ...

  2. android波纹效果弹窗,Android自定义View实现波纹效果

    Android自定义View实现波纹效果 时间:2017-05-27     来源:移动互联网学院 1.引言:随着Android智能手机的普及,Android应用得到了大力支持,而Android应用的 ...

  3. android圆形波纹按钮,android自定义View——圆形波纹扫描效果

    蓝牙项目,考虑到后面可能会用到这个扫描的效果,所以参照大神写好的控件,增加了自己需要使用的接口.也顺便巩固一下自定义view中各种零碎的知识点. 需要的效果图 先放一个效果图,点击中心图片开始动画,再 ...

  4. android覆盖扩散动画,[Android]多层波纹扩散动画——自定义View绘制

    之前整理过一些属性动画的基本操作,这一段时间的动画相关需求都安然度过了.直到这次-- 一.另一种动画需求 多数交互中的动画都是让单个页面元素动起来,这种就很适合用属性动画实现.但是对于 多个元素.非页 ...

  5. android开发控件水波纹,Android实现水波纹控件的方法

    有很多app使用过水波纹的这样的效果,看着很酷酷的样子,所以自己就撸码写了一个. 实现思路: 利用贝塞尔曲线绘制圆弧(也就是水波的波纹) 通过动画改变绘制的起始点使水波纹平移 首先,定义我们需要的自定 ...

  6. Android Material Design 之 Activity 跳转水波纹扩散动画

    博主声明: 转载请在开头附加本文链接及作者信息,并标记为转载.本文由博主 威威喵 原创,请多支持与指教. 本文首发于此   博主:威威喵  |  博客主页:https://blog.csdn.net/ ...

  7. android 自定义progressbar demo,Android自定义View――动态ProgressBar之模仿360加速球

    在之前一篇文章中我们讲解了三种ProgressBar的做法,详见-><Android 自定义View--自定义ProgressBar >.这一节中我们模仿360加速球制作一个动态Pr ...

  8. android前台渲染图片,自定义View

    android前台渲染,主要是重写view的ondraw方法,在canvas里操作 自定义MyView类 package com.ssln;import android.annotation.Supp ...

  9. 球体动画Android,Android自定义View实现简单炫酷的球体进度球实例代码

    前言 最近一直在研究自定义view,正好项目中有一个根据下载进度来实现球体进度的需求,所以自己写了个进度球,代码非常简单.先看下效果: 效果还是非常不错的. 准备知识 要实现上面的效果我们只要掌握两个 ...

最新文章

  1. Java并发编程(十一)——原子操作CAS
  2. 数字原生,创新生长|企业如何打造数字创新的“飞天梦”?
  3. 【AI不惑境】模型压缩中知识蒸馏技术原理及其发展现状和展望
  4. WCF系列学习笔记4之绑定详解
  5. Android全工程编译不过问题汇总
  6. python代码格式
  7. Predicate函数式接口
  8. 做arma模型步骤_互助问答第349期:关于ARMA预测模型的问题
  9. c语言中栈的作用,栈(Stack)的概念和应用及C语言实现
  10. Linux 命令(85)—— md5sum 命令
  11. 关于scala中lazy val的几个注意事项
  12. python文件下载学习
  13. “rt.jar is not on its project's build path”
  14. Cesium 之实现房屋模型拆解
  15. 解决谷歌自带翻译不出现问题
  16. Vs code PIO一直loading
  17. 《Excel高手捷径:一招鲜,吃遍天》一第29招 Excel 文件“减肥瘦身”秘诀
  18. windows虚拟摄像头开发
  19. Javascript中的作用域,作用域链
  20. 萤石视频监控模式的参数decoderPath配置问题

热门文章

  1. SAP UI5 workthrough 12 sap.m.shell
  2. how is SAP UI5 Model.setProperty implemented
  3. Marketing Cloud的notification的OData实现
  4. 一种简单的不需要查询UI5文档就能获得所有API的小技巧
  5. SAP Leonardo 机器学习插件的安装
  6. deactivate Data synchronization
  7. 如何控制product search attribute支持的操作类型
  8. how is sap-ui-core.js initialize the reqeust of sap-ui-core-dbg.js
  9. get metadata in QHD - still has cache logic
  10. SAP CRM产品主数据的附件信息在搜索时就已经从后台被读取了