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开发中 ...
随机推荐
- UVa 1471 防线
https://vjudge.net/problem/UVA-1471 题意:给出一个序列,删除一个连续子序列,使得剩下的序列中有一个长度最大的连续递增子序列,输出个数. 思路:首先可以计算出以i结尾 ...
- 微信网页跳转页面常见bug处理
微信网页跳转页面常见bug处理 1.不要直接用a链接直接跳转 2.url后加上时间戳 function gohome() { window.location.href = "../home/ ...
- Java中Arrays 与 Collections 的简单操作
import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.C ...
- Java jdbc访问sqlserver,oracle数据库 DEMO
1.JDBC访问Oracle数据库 public class Jdbc_Oracle { // 静态代码块,只会执行一次,类似C#静态构造方法 static { try { // 加载数据库驱动一次 ...
- 简单介绍tomcat中maxThreads,acceptCount,connectionTimeout
<?xml version='1.0' encoding='utf-8'?> <Server port="8005" shutdown="SHUTDOW ...
- chrome的url列表里面也找不到chrome://plugins的原因
plugins 页面被移除后,可以访问: chrome://settings/content 调整 Flash.PDF 的设置. 原本 plugins 页面就基本只剩下这两货了,移除掉确实没啥影响. ...
- Bata冲刺 第一天
一.冲刺第一天完成任务情况及贡献小时数: 姓名 今日已完成任务 时间(h) 马仲山 代码调整 2 马婧(12) 整理需求文档 2 马婧(13) 整理设计文档 2 马世芳 编写测试文档 2 张俊逸 ...
- js 几个重要的特性
背景: 语法借鉴 java 函数借鉴 scheme 原型继承借鉴 self 正则表达式借鉴 Perl 1.动态语言 函数的定义和调用 形参与实参不需要一致 形参可由 argu ...
- Html概述
Html概述 主要思想,主要思想很重要 一.Html是什么 一种标记语言(用标签进行标记) 对要显示的文字进行标记 二.Html核心 标签(只认标签) 封装,所以必须有头尾,你才知道标签的范围,你才知 ...
- [Java学习] Java多态和动态绑定
在Java中,父类的变量可以引用父类的实例,也可以引用子类的实例. 请读者先看一段代码: 1. public class Demo { 2. public static void main(Strin ...
