今天来实现一个类似于网易云音乐类似的动态效果,在用网易云音乐听歌时会有一个类似这样的效果,如下:

而咱们这次要实现的效果如下:

music图形的绘制:

在实现动画之前先来将静态的图形绘制出来, 如下:

首先绘制两个圆,如下:

所以新建一个自定义View,如下:

/**
* 音乐加载View
* 首先绘制静态图形
*/
public class MusicLoadingView extends View { //variables
private Paint paint; public MusicLoadingView(Context context) {
this(context, null);
} public MusicLoadingView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, -1);
} public MusicLoadingView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
} private void init() {
paint = new Paint();
paint.setColor(Color.BLACK);
paint.setAntiAlias(true);
} @Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//1、首先绘制两个圆(大圆和小圆)
//2、绘制两段对称的弧
}
}

而绘制圆需要确定圆心和半径,而这两个值的确定需要先知道圆的直径,而这里的直径取咱们自定义View的宽高的最小值,如下:

有了这个直径之后,接下来先绘制大圆了,如下:

此时编译运行:

呃~~不是空心的,那简单,更改画笔的样式既可:

再次运行:

接下来再来绘制中心的小圆,很显然需要给这个小圆定义一下它的半径,所以:

编译运行:

嗯~~但是对比最终效果发现这个小圆的线太细了,那就加粗呗,如下:

编译运行:

但是!!!大圆太贴边了,都有点被切的感觉,如下:

所以应该将其与View的边界有一定间隔,很简单,将大圆的半径缩小一点既可,如下:

大小圆目前已经绘制好了,接下来则需要要圆上绘制两段弧,如下:

关于如何绘制弧通过之前的练习已经非常熟悉了,这里就不过多解释,只是需要说明的一点,上面两段对立的弧其角度相差180度,很容易理解,所以接下来先绘制一对弧,如下:

/**
* 音乐加载View
* 首先绘制静态图形
*/
public class MusicLoadingView extends View { //constants
/* 小圆的半径 */
private static final float SMALL_RADIUS = 5f;
private static final float SWEEP_ANGLE = 80f; //variables
private Paint paint;
/* 大圆的直径:取屏幕宽高的较小值 */
private int length; public MusicLoadingView(Context context) {
this(context, null);
} public MusicLoadingView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, -1);
} public MusicLoadingView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
} private void init() {
paint = new Paint();
paint.setColor(Color.BLACK);
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.STROKE);//设置成空心的样式
} @Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
length = Math.min(w, h);
} @Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//1、首先绘制两个圆(大圆和小圆)
paint.setStrokeWidth(2);
canvas.drawCircle(length / 2, length / 2, length / 2 - SMALL_RADIUS, paint);//大圆
paint.setStrokeWidth(5);
canvas.drawCircle(length / 2, length / 2, SMALL_RADIUS, paint);//小圆 //2、绘制两段对称的弧
RectF rectF = new RectF(length / 2 - length / 3, length / 2 - length / 3, length / 2 + length / 3, length / 2 + length / 3);
canvas.drawArc(rectF, 0, SWEEP_ANGLE, false, paint);//第一段弧
canvas.drawArc(rectF, 180, SWEEP_ANGLE, false, paint);//第一段对称弧
}
}

其外切矩形就是以大圆的直径为参照来定的,这个可以根据实际业务场景动态去决定,下面编译运行一下:

嗯~~弧正常被设置了,不过貌似太粗了,原因是由于它是在绘制小圆之后进行绘制的,而小圆更改了画笔的粗度,要改细咱们可以将下面代码进行对换一下:

此时再次编译运行:

接下来再来绘制另外一对弧那就依葫芦画瓢呗,只是说弧度比刚才的要小一点,直接上代码:

编译运行:

至此~~静态效果就已经实现啦,接下来则想办法让其动起来。

music图形动画实现:

此次的动画实现还是跟上一次WIFI【http://www.cnblogs.com/webor2006/p/8322387.html】的实现思路类似,纯代码来控制而不采用Android提供的动画,在上一次中是采用Handler的方式来按一定的时间不断去调用invalidate()来达到不断绘制的目的,如:

对于这一次的实现思路基本类似,但是这次不采用handler了,而是直接在onDraw()方法中不断调用invalidate()方法,因为这次的动画本身要求就是不断绘制不需要加延时,所以:

而最终效果关键之所在在于两对弧不断的在“运动”,而弧的具体位置的改变也就是在绘制弧形时的startAngle来决定,所以咱们需要将弧的开始角度提成变量,以便在onDraw()方法中不断去更改起始角度来达到"运动"的目的,所以:

/**
* 音乐加载View
* 首先绘制静态图形
*/
public class MusicLoadingView extends View { //constants
/* 小圆的半径 */
private static final float SMALL_RADIUS = 5f;
private static final float SWEEP_ANGLE = 80f; //variables
private Paint paint;
/* 大圆的直径:取屏幕宽高的较小值 */
private int length;
/* 第一条弧的起始角度 */
private float startAngle1 = 0;
/* 第二条对称弧的起始角度 */
private float startAngle2 = 180; public MusicLoadingView(Context context) {
this(context, null);
} public MusicLoadingView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, -1);
} public MusicLoadingView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
} private void init() {
paint = new Paint();
paint.setColor(Color.BLACK);
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.STROKE);//设置成空心的样式
} @Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
length = Math.min(w, h);
} @Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//1、首先绘制两个圆(大圆和小圆)
paint.setStrokeWidth(5);
canvas.drawCircle(length / 2, length / 2, SMALL_RADIUS, paint);//小圆
paint.setStrokeWidth(2);
canvas.drawCircle(length / 2, length / 2, length / 2 - SMALL_RADIUS, paint);//大圆 //2、绘制两段对称的弧
RectF rectF = new RectF(length / 2 - length / 3, length / 2 - length / 3, length / 2 + length / 3, length / 2 + length / 3);
canvas.drawArc(rectF, startAngle1, SWEEP_ANGLE, false, paint);//第一段弧
canvas.drawArc(rectF, startAngle2, SWEEP_ANGLE, false, paint);//第一段对称弧 rectF = new RectF(length / 2 - length / 4, length / 2 - length / 4, length / 2 + length / 4, length / 2 + length / 4);
canvas.drawArc(rectF, startAngle1, SWEEP_ANGLE, false, paint);//第二段弧
canvas.drawArc(rectF, startAngle2, SWEEP_ANGLE, false, paint);//第二段对称弧 invalidate();
}
}

接着每次绘制时不断改变其角度,如下:

此时编译运行就是在开篇所看到的效果了,另外还差一个收尾工作,就是当app退出时的处理,目前onDraw()是不断在重绘,所以需要控制一下生命周期合理释放资源,在上次wifi的资源释放时是采用给View增加一个onDestroy()在Activity退出时主动调一下,而这次不借助Activity了,而是在View中能知道什么时候销毁了,具体做法如下:

/**
* 音乐加载View
* 首先绘制静态图形
*/
public class MusicLoadingView extends View { //constants
/* 小圆的半径 */
private static final float SMALL_RADIUS = 5f;
private static final float SWEEP_ANGLE = 80f; //variables
private Paint paint;
/* 大圆的直径:取屏幕宽高的较小值 */
private int length;
/* 第一条弧的起始角度 */
private float startAngle1 = 0;
/* 第二条对称弧的起始角度 */
private float startAngle2 = 180;
/*是否不断绘制,用来控制生命周期*/
private boolean isLoopDraw = true; public MusicLoadingView(Context context) {
this(context, null);
} public MusicLoadingView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, -1);
} public MusicLoadingView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
} private void init() {
paint = new Paint();
paint.setColor(Color.BLACK);
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.STROKE);//设置成空心的样式
} @Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
length = Math.min(w, h);
} @Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
startAngle1 += 3;
startAngle2 += 3;
//1、首先绘制两个圆(大圆和小圆)
paint.setStrokeWidth(5);
canvas.drawCircle(length / 2, length / 2, SMALL_RADIUS, paint);//小圆
paint.setStrokeWidth(2);
canvas.drawCircle(length / 2, length / 2, length / 2 - SMALL_RADIUS, paint);//大圆 //2、绘制两段对称的弧
RectF rectF = new RectF(length / 2 - length / 3, length / 2 - length / 3, length / 2 + length / 3, length / 2 + length / 3);
canvas.drawArc(rectF, startAngle1, SWEEP_ANGLE, false, paint);//第一段弧
canvas.drawArc(rectF, startAngle2, SWEEP_ANGLE, false, paint);//第一段对称弧 rectF = new RectF(length / 2 - length / 4, length / 2 - length / 4, length / 2 + length / 4, length / 2 + length / 4);
canvas.drawArc(rectF, startAngle1, SWEEP_ANGLE, false, paint);//第二段弧
canvas.drawArc(rectF, startAngle2, SWEEP_ANGLE, false, paint);//第二段对称弧 if (isLoopDraw)
invalidate();//让View不断重绘
} //当自定义控制脱离窗体,即将销毁的时候会被调用
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
Log.e("cexo", "MusicLoadingView.onDetachedFromWindow()");
isLoopDraw = false;
}
}

最后运行在退出时可以看到它被调用了,如下:

至此~效果完美实现!

动画学习之Music图形绘制的更多相关文章

  1. 动画学习之WIFI图形绘制

    Android原生动画概述: 对于APP开发中涉及到的一些动画基本上都可以用Android提供的各种原生动画类来实现,所以在学习自定义动画之前首先来对原生动画进行一个基本的了解,这里不详细对每一个原生 ...

  2. [html] 学习笔记-Canvas图形绘制处理

    使用Canvas API 可以将一个图形重叠绘制在另外一个图形上,也可以给图形添加阴影效果. 1.Canvas 图形组合 通过 globalCompositeOperation = 属性 来指定重叠效 ...

  3. cocos2d-x学习记录4——图形绘制

    重写CCNode的draw函数能够绘制出各种基本图形,如点.直线.多边形.园.贝塞尔曲线等,同时还可以设置绘制的颜色和宽度. MyScene的draw函数 void MyScene::draw() { ...

  4. matlab学习笔记8 基本绘图命令-特殊图形绘制

    一起来学matlab-matlab学习笔记8 基本绘图命令_3 特殊图形绘制 觉得有用的话,欢迎一起讨论相互学习~Follow Me 参考书籍 <matlab 程序设计与综合应用>张德丰等 ...

  5. Canvas学习:封装Canvas绘制基本图形API

    Canvas学习:封装Canvas绘制基本图形API Canvas Canvas学习   从前面的文章中我们了解到,通过Canvas中的CanvasRenderingContext2D对象中的属性和方 ...

  6. HTML5图形绘制学习(1)-- Canvas 元素简介

    Canvas元素是HTML5中新增的一个专门用来进行图形绘制的元素.和其名称Canvas一样,它就相当于一个画布,我们可以在其上描绘各种图形. 这里所说的绘制图型,不是指我们可以进行可视化的图形绘制, ...

  7. matlab学习笔记之五种常见的图形绘制功能

    分类: 离散数据图形绘制 函数图形绘制 网格图形绘制 曲面图形绘制 特殊图形绘制 本文重点介绍matlab五种图形绘制方法的后三种. 一.网格图形绘制 以绘制函数z=f(x,y)三维网格图为例,下面为 ...

  8. iOS动画学习-视觉效果

    CALayer不仅仅是iOS动画学习-CALayer中介绍的那些内容,他还有一些其他属性,比如shadowColor,borderWidth,borderColor等等,这些属性我们只需要简单点设置就 ...

  9. SVG 学习<一>基础图形及线段

    目录 SVG 学习<一>基础图形及线段 SVG 学习<二>进阶 SVG世界,视野,视窗 stroke属性 svg分组 SVG 学习<三>渐变 SVG 学习<四 ...

随机推荐

  1. CentOS 升级至指定版本

    CentOS系统下用yum upgrade命令只能升级到最新版本,CentOS仓库并不维护历史版本,所以只能使用 vault.centos.org 历史版本快照进行更新.本文以将7.0.1406升级到 ...

  2. 对于MVVM的理解

    MVVM 是Model-View-ViewModel的缩写. Model 代表数据模型,也可以在model中定义数据修改和操作的业务逻辑. View 代表UI组件,负责姜黄素局模型转化成UI展现出来. ...

  3. CTF—攻防练习之HTTP—命令执行漏洞

    渗透环境: 主机:192.168.32.152 靶机:192.168.32.1 命令执行漏洞 命令执行漏洞概念:当应用需要调用一些外部程序去处理内容的情况下,就会用到一些执行系统命令的函数.如PHP中 ...

  4. Python爬虫学习==>第十章:使用Requests+正则表达式爬取猫眼电影

    学习目的: 通过一个一个简单的爬虫应用,初窥门径. 正式步骤 Step1:流程框架 抓取单页内容:利用requests请求目标站点,得到单个页面的html代码,返回结果: 正则表达式分析:根据html ...

  5. C#编程 线程,任务和同步(2) 开启线程

    创建线程的几种方法: 1 异步委托 创建线程的一种简单方式是定义一个委托,并异步调用它. 委托是方法的类型安全的引用.Delegate类 还支持异步地调用方法.在后台,Delegate类会创建一个执行 ...

  6. 技术简历写这么写,才能得到BAT面试官们的青睐

    公众号[程序员江湖] 作者陆小凤,985 软件硕士,阿里 Java 研发工程师,在技术校园招聘.自学编程.计算机考研等方面有丰富经验和独到见解,目前致力于分享程序员干货和学习经验,同时热衷于分享作为程 ...

  7. HCL试验5

    PC端配置:配置ip地址 交换机1配置:①创建VLAN system-view vlan 10 vlan 20 ②配置PC端接口 interface gi 1/0/1 port link-type a ...

  8. 【AMAD】django-guradian -- 为Django加入单个对象级别的权限

    动机 简介 个人评分 动机 django默认的permission系统就是将将能用的程度.默认授权会将一个数据表所有数据的权限都授予,而现实世界不是这样.很多时候,我们仅想授权数据的一小部分给用户. ...

  9. 【DSP开发】C6678的中断控制器

    分两层,一层是每个core内部的中断控制器,这个叫interrupt controller,简写intc:一层是整个芯片的,属于芯片级的,在每个core的外面,这个叫chip-level interr ...

  10. 前端数据Mock

    参考链接:https://www.clloz.com/programming/front-end/js/2019/05/10/data-mock/?utm_medium=hao.caibaojian. ...