Android 自定义圆形旋转进度条,仿微博头像加载效果
微博 App 的用户头像有一个圆形旋转进度条的加载效果,看上去效果非常不错,如图所示:
据说 Instagram 也采用了这种效果。最近抽空研究了一下,最后实现的效果是这样:
基本上能模拟出个大概,代码量不大,来讲讲实现思路吧。
模拟一种动画效果,首先需要仔细分析其运作过程,找到其中的物理规律,从而确定实现方案。像这种运动速度较快的动画,一般不是很容易看清。可以先通过录屏软件,录取动画运作的过程,然后借助一些辅助工具放慢放大,比如 PS,反复重复播放几遍,基本上就能看出动画的运作规律了。
回到这里的加载效果,拆分开来,可以理解为画笔上的两层绘制和时间上的两段过程。时间上,很明显可以看出分为前 360 度和后 360 度,主要在画笔上:
1,单一完整的圆弧绘制。前 360 度,从 360 度的圆弧到 0 度圆弧的递减过程;后 360 度,从 0 度圆弧到 360 度圆弧的递增过程。
2,重复片段的圆弧绘制。前 360 度,从零开始,逐渐递增,直到多段填满圆周;后 360 度,反过来,逐渐递减,直到数量为零。
其他的就是细节的处理,后面具体实现时再提及,我们先来看看如何实现这两个核心流程的绘制。
由于这两个流程使用的画笔属性相同,所以使用一个 Paint 对象即可,这段代码没什么好讲的,就是一些初始化工作:
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(mArcWidth);
mPaint.setStrokeCap(Paint.Cap.ROUND);
注意,与微博原图效果不同的是,我的效果图中使用到了渐变色圆环,这样效果更好看一些。使用 setShader() 方法可以给画笔设置渐变色,实现方式是:
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
......
Shader shader = new LinearGradient(0f, 0f, mWidth, mHeight,
mStartColor, mEndColor, Shader.TileMode.CLAMP);
mPaint.setShader(shader);
}
Shader 子类有很多,这里使用的是线性渐变类 LinearGradient,由于需要使用 View 宽高,所以放在了 onSizeChanged() 函数里面。
核心计算和绘制工作都在 onDraw() 方法里面,看下这里的代码:
@Override
protected void onDraw(Canvas canvas) {
if (maxAngle <= 360) {
float angle = 0;
canvas.rotate(mRatio * maxAngle / 360, mWidth / 2, mHeight / 2);
canvas.drawArc(mRectF, maxAngle, 360 - maxAngle, false, mPaint);
while (angle <= maxAngle) {
float length = mArcRadian * angle / maxAngle;
canvas.drawArc(mRectF, 0, length, false, mPaint);
canvas.rotate(mArcSpacing, mWidth / 2, mHeight / 2);
angle += mArcSpacing;
}
} else {
float angle = 0;
canvas.rotate(mRatio + mRatio * (maxAngle - 360) / 360, mWidth / 2, mHeight / 2);
canvas.drawArc(mRectF, 0, maxAngle - 360, false, mPaint);
canvas.rotate(maxAngle - 360, mWidth / 2, mHeight / 2);
while (angle <= 720 - maxAngle) {
float length = mArcRadian * angle / (720 - maxAngle);
canvas.drawArc(mRectF, 0, length, false, mPaint);
canvas.rotate(mArcSpacing, mWidth / 2, mHeight / 2);
angle += mArcSpacing;
}
}
if (maxAngle <= 720) {
maxAngle += mArcSpacing;
postInvalidateDelayed(30);
}
}
前面提到,动画在时间上分前后 360 度的两段过程,所以这里定义了一个 maxAngle 变量来定义时间的变化。可以看到,前后 360 度的绘制代码看上去差不多,但还是有很大区别的。需要理解的地方有:
1,多个小段圆弧可以利用画布旋转的方式轻松实现,也就是 canvas.rotate() 方法,上面代码中的 while 循环部分。这里有个细节处理,就是每段圆弧的弧度有个递增变化。
2,整个 View 给人的感觉有一种旋转的效果,为了实现这个效果,在每次绘制前,都增加了旋转的步骤,也就是这行代码:
canvas.rotate(mRatio * maxAngle / 360, mWidth / 2, mHeight / 2);
其中 mRatio 表示整个动画结束时,View 相比初始状态时整体旋转的角度。 这里我设置的默认值是 60,值越大,动画执行时呈现出越快的旋转效果。大家可以修改源码,自己尝试一下。
3,还有一点就是,maxAngle 变量每次增量值的设置,一定要设置为相邻两段片段圆弧的间距弧度。这样做的目的是,保证每次绘制,片段圆弧都能有一个完整的递增或递减。否则,动画执行时,看上会发生视觉上的抖动效果。
基本上就是这样,代码量虽然不多,但是各种细节的处理还是耗费了很多时间调整。本来想使用一些图例展示一下每行代码的作用,但是太费时间了。如果感兴趣的,完全可以自己下载一下源码,修改试试看。
经过简单地封装,提取出一部分属性:
<declare-styleable name="CircleLoadingView">
<attr name="circleStartColor" format="color|reference"/>
<attr name="circleEndColor" format="color|reference"/>
<attr name="circleArcWidth" format="integer|reference"/>
<attr name="circleArcRadian" format="integer|reference"/>
<attr name="circleArcSpacing" format="integer|reference"/>
</declare-styleable>
注意:中间的头像部分不是这里自定义 View 的内容,使用时可以自由填充内容。比如,看下我这里的使用方式,还是比较自由的:
<RelativeLayout
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_centerInParent="true">
<com.yifeng.view.view.CircleLoadingView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:circleStartColor="#ffff00"
app:circleEndColor="#ff0000"
app:circleArcRadian="5"
app:circleArcWidth="10"
app:circleArcSpacing="10"/>
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="10dp"
android:src="@mipmap/ic_avatar_default"/>
</RelativeLayout>
源代码还是老样子,统一在 GitHub 上的自定义 View 集锦库里,地址如下。:
https://github.com/Mike-bel/android-custom-views
关于我:亦枫,博客地址:http://yifeng.studio/,新浪微博:IT亦枫
微信扫描二维码,欢迎关注我的个人公众号:安卓笔记侠
不仅分享我的原创技术文章,还有程序员的职场遐想
Android 自定义圆形旋转进度条,仿微博头像加载效果的更多相关文章
- Android自定义圆角矩形进度条2
效果图: 或 方法讲解: (1)invalidate()方法 invalidate()是用来刷新View的,必须是在UI线程中进行工作.比如在修改某个view的显示时, 调用invalidate()才 ...
- Android开发-各种各样好看漂亮的进度条,指示器,加载提示汇总
导读:之前项目中用到一些进度条,找了不少,打算写个demo自己总结一下,留着以后用, 有些是自己写的,有些是github上找的别人的库,如果大家觉得好看可以用,直接下载复制代码到项目里就可以用,ok ...
- Android自定义View(LimitScrollerView-仿天猫广告栏上下滚动效果)
转载请标明出处: http://blog.csdn.net/xmxkf/article/details/53303872 本文出自:[openXu的博客] 1分析 2定义组合控件布局 3继承最外层控件 ...
- 灵活、可高度自定义的——Progress进度圈、弹窗、加载进度、小菊花
DDProgressHUD的介绍 提供了四种类型的展示: 显示无限旋转的加载图(比如小菊花,可以自定义),显示文字信息.网络刷新时经常用到. 显示加载进度的动画,也可以显示文字.网络下载时用的比较多, ...
- Unity跳转场景进度条制作教程(异步加载)
Unity跳转场景进度条制作 本文提供全流程,中文翻译. Chinar 坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) Chinar -- 心分享 ...
- ajax 上传文件,显示进度条,进度条100%,进度条隐藏,出现卡顿就隐藏进度条,显示正在加载,再显示上传完成
<form id="uploadForm" method="post" enctype="multipart/form-data"&g ...
- 自定义ListView实现下拉刷新,下拉加载的功能
package com.loaderman.myrefreshlistviewdemo; import android.content.Context; import android.util.Att ...
- Android简易实战教程--第十七话《自定义彩色环形进度条》
转载请注明出处:http://blog.csdn.net/qq_32059827/article/details/52203533 点击打开链接 在Android初级教程里面,介绍了shape用法 ...
- Android零基础入门第52节:自定义酷炫进度条
原文:Android零基础入门第52节:自定义酷炫进度条 Android系统默认的ProgressBar往往都不能满足实际开发需要,一般都会开发者自定义ProgressBar. 在Android开发中 ...
随机推荐
- [ios]ios语音识别
参考:http://blog.sina.com.cn/s/blog_923fdd9b0101flx1.html 通过谷歌语音接口的实现语音识别 最近在项目中有需要实现语音识别的功能.折腾了几天才搞好. ...
- [ios]"The identity used to sign the executable is no longer valid"错误解决方法
重新去开发者网站,申请一遍profiles 参考:http://www.bubuko.com/infodetail-982908.html 我出现这个错误的情况,程序提交app store之后,第二天 ...
- 《剑指offer》第二十六题(树的子结构)
// 面试题26:树的子结构 // 题目:输入两棵二叉树A和B,判断B是不是A的子结构. #include <iostream> struct BinaryTreeNode { doubl ...
- 30分钟了解Shiro与Springboot的多Realm基础配置
写在前面的话: 我之前写过两篇与shiro安全框架有关的博文,居然能够广受欢迎实在令人意外.说明大家在互联网时代大伙对于安全和登录都非常重视,无论是大型项目还是中小型业务,普遍都至少需要登录与认证的逻 ...
- 算法笔记--st表
概述:用倍增法求区间最值的离线算法,O(nlogn)预处理,O(1)访问. 预处理: 状态:st[i][j]:[i,i+2^j)之间的最值 状态转移:如果j等于0,st[i][j]=a[i] 如果j大 ...
- C++ 利用栈解决运算问题
2017-06-27 19:19:18 第一步需要将中缀表达式转为后缀表达式.这步的转化可以说是本题的核心. 主要的转化手段是利用栈,有如下几个规则: 数字直接输出 "("直接进栈 ...
- Java JDK5新特性-可变参数
2017-10-31 00:19:07 可变参数:定义方法的时候不知道该定义多少个参数 格式:修饰符 返回值类型 方法名(数据类型... 变量名){} 注意:这里的变量其实是一个数组 ...
- English trip WeekEnd-Lesson 2018.11.10
本周末上了三节课,做个小结吧\(^o^)/~: [102] 新概念一早读 - 27 - 28 Teacher: March Mrs. Smith's living room is lar ...
- Confluence 6 LDAP 用户结构设置
用户对象类(User Object Class) 这个是在 LDAP 用户对象中对用户分类的名字.例如: user 用户对象过滤器(User Object Filter) 当对用户对象进行搜索的时候 ...
- Serega and Fun CodeForces - 455D (分块 或 splay)
大意:给定n元素序列, 2种操作 将区间$[l,r]$循环右移1位 询问$[l,r]$中有多少个等于k的元素 现在给定q个操作, 输出操作2的询问结果, 强制在线 思路1: 分块 每个块内维护一个链表 ...
