版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、Material-ish Progress 源码阅读很明显第一个控件是默认情况下的,而第二个就是我改动过的控件。这个控件的制作,我们先着重来看动效部分,毕竟如果静止状态的话其实是有很多种方法来实现的,第一步我们先不去理睬静态这一部分。撇去细节,我们从大的方向入手,我把这个动效分为两个部分:第一部分:圆弧的动态绘制。这一部分,只要看第二个 progress 就行了,这里要做的就是计算每一段时间内要绘制的部分,不管是最初的由最小变最大,还是之后的最大变最小。第二部分:圆弧的滚动。其实准确来说,是对起始角度的计算。第一个 progress 融合了第一部分和第二部分,圆弧的大小和起始点的不断变化的结合
2、就是一个完整的 material progressbar。分析前的准备API:/ 从开机到现在的毫秒数SystemClock.uptimeMillis()/ 绘制圆弧canvas.drawArc(circleBounds, from, length, false, barPaint);函数:/在开始与结束的地方速率改变比较慢,在中间的时候加速(float)(Math.cos(input + 1) * Math.PI) / 2.0f) + 0.5f/在开始的地方速率改变比较慢,然后开始加速Math.pow(input, 2)/在开始的地方快然后慢1.0f - (1.0f - input) * (
3、1.0f - input)以上只是部分函数,如果想要看更多,可以看看我的这篇简单的插值器文章 Android动画-Interpolator(插值器)大全,里面介绍了常用的插值器,想要知道怎么实现的,看看源码就知道了,其实就是一些函数的使用,数学都还给我体育老师了,这个没法讲,希望有好文章的童鞋可以推荐下,不胜感激。列出这些函数的意义其实就是想告诉看源码的童鞋,看源码不要纠结在细节上,有些东西确实不是一时半会儿能弄懂的。对于本章的含义就是,不要纠结于函数的由来,只需要知道这是用来做什么的。还有一些参数我就不一一介绍了,都是比较简单的参数,于逻辑无碍。到此,因该说基本的准备都OK了,接下来就是看源
4、码了。思路从不熟悉控件源码的角度来讲,这里就讲思路确实不太合适,但是在接下来的源码解析中,却很难穿插思路的讲解,因为每一行代码都多少需要联系到其它的代码才能准确解读出代码的意义,而且还有很多细节的处理,那时候再来说思路就显得过于混乱了,如果能在这里明白控件的思路,我觉得看者完全可以自己去看源码,相信会比我这生涩的分析更加清晰。这里的思路也是需要联系到前面介绍的参数,这样讲解会更清晰点,我们从控件伊始开始分析:控件从最小圆弧角度 barLength 开始,经历了 pausedTimeWithoutGrowing ( pausedTimeWithoutGrowing >= pauseGrow
5、ingTime )的时间后,开始计算需要绘制的总角度:总角度 = barLength + 需要额外绘制的角度。而这个需要额外绘制的角度 = 已经经历的时间 × ( barMaxLength - barLength) / barSpinCycleTime。而当到达最大角度之后,我们就需要减去相应的时间内对应的角度: 需要额外绘制的角度 = ( barMaxLength - barLength) - 已经经历的时间 × ( barMaxLength - barLength) / barSpinCycleTime,前者的计算是为了圆弧逐渐增大,后者则是为了逐渐变小。最后,需要小小
6、的强调下:起始角度的计算也非常重要。源码分析控件的全部代码只有 800 行,有效代码目测只有 1/3,这里我们就不看 onMeasure 和 onSizeChanged 这些准备工作的处理代码了,只是一些测量和初始化的工作代码,那么 onDraw 里面的代码以及涉及到的相关函数每一行都是必不可少的。onDraw protected void onDraw(Canvas canvas) super.onDraw(canvas); / 圆弧背景 canvas.drawArc(circleBounds, 360, 360, false, rimPaint); boolean mustInvalida
7、te = false; if (!shouldAnimate) return; if (isSpinning) /Draw the spinning bar mustInvalidate = true; long deltaTime = (SystemClock.uptimeMillis() - lastTimeAnimated); updateBarLength(deltaTime); float deltaNormalized = deltaTime * spinSpeed / 1000.0f;/ mProgress += deltaNormalized; if (mProgress &g
8、t; 360) mProgress -= 360f; / A full turn has been completed / we run the callback with -1 in case we want to / do something, like changing the color runCallback(-1.0f); lastTimeAnimated = SystemClock.uptimeMillis(); float from = mProgress - 90; float length = barLength + barExtraLength; if (isInEdit
9、Mode() from = 0; length = 135; canvas.drawArc(circleBounds, from, length, false, barPaint); else float oldProgress = mProgress; if (mProgress != mTargetProgress) /We smoothly increase the progress bar mustInvalidate = true; float deltaTime = (float) (SystemClock.uptimeMillis() - lastTimeAnimated) /
10、1000; float deltaNormalized = deltaTime * spinSpeed; mProgress = Math.min(mProgress + deltaNormalized, mTargetProgress); lastTimeAnimated = SystemClock.uptimeMillis(); if (oldProgress != mProgress) runCallback(); float offset = 0.0f; float progress = mProgress; if (!linearProgress) Log.d(TAG, "
11、do factor"); float factor = 2.0f; offset = (float) (1.0f - Math.pow(1.0f - mProgress / 360.0f, 2.0f * factor) * 360.0f; progress = (float) (1.0f - Math.pow(1.0f - mProgress / 360.0f, factor) * 360.0f; if (isInEditMode() progress = 360; canvas.drawArc(circleBounds, offset - 90, progress, false,
12、barPaint); if (mustInvalidate) invalidate(); 在参数准备的环节已经介绍了 isSpinning 这个参数,所以当 isSpinning 为 true 的时候,便是我们首要分析的代码部分 动效代码。if ( isSpinning = true ) mustInvalidate = true; long deltaTime = (SystemClock.uptimeMillis() - lastTimeAnimated); updateBarLength(deltaTime); float deltaNormalized = deltaTime * sp
13、inSpeed / 1000.0f; mProgress += deltaNormalized; if (mProgress > 360) mProgress -= 360f; / A full turn has been completed / we run the callback with -1 in case we want to / do something, like changing the color runCallback(-1.0f); lastTimeAnimated = SystemClock.uptimeMillis(); float from = mProgr
14、ess - 90; float length = barLength + barExtraLength; if (isInEditMode() from = 0; length = 135; canvas.drawArc(circleBounds, from, length, false, barPaint);在 onDraw 方法调用时,每次都初始化一个参数boolean mustInvalidate = false;,这个参数便是判断是否重绘当前控件,在 isSpinning 为 true 的情况下,很明显这是一个死循环,在 onDraw 的最后几行: if (mustInvalidate
15、) invalidate(); 这里的判断保证了无线循环。long deltaTime = (SystemClock.uptimeMillis() - lastTimeAnimated);相对于之前绘制的时间,到现在的需要绘制的时间的时间差。如果你看了思路部分的文字的话,那么很方便就可以将这个变量理解为 已经历的时间。这个参数不但是用来计算 圆弧需要绘制角度 的重要参数,还是用来计算 圆弧起始角度 的重要参数。lastTimeAnimated 的赋值在控件显示的时候 Override protected void onVisibilityChanged(View changedView, in
16、t visibility) super.onVisibilityChanged(changedView, visibility); if (visibility = VISIBLE) lastTimeAnimated = SystemClock.uptimeMillis(); 还有就是在完成了一系列的运算之后,最后给 lastTimeAnimated 赋值 lastTimeAnimated = SystemClock.uptimeMillis();updateBarLength(deltaTime) 用于计算圆弧额外绘制角度的函数,非常重要!可以说看懂这个函数就看懂了一切。需要注意的是,这个函
17、数的分析需要和onDraw方法结合看才行。private void updateBarLength(long deltaTimeInMilliSeconds) if (pausedTimeWithoutGrowing >= pauseGrowingTime) timeStartGrowing += deltaTimeInMilliSeconds; if (timeStartGrowing > barSpinCycleTime) / We completed a size change cycle / (growing or shrinking) timeStartGrowing -
18、= barSpinCycleTime; /if(barGrowingFromFront) pausedTimeWithoutGrowing = 0; / barGrowingFromFront = !barGrowingFromFront; float distance = (float) Math.cos(timeStartGrowing / barSpinCycleTime + 1) * Math.PI) / 2 + 0.5f; float destLength = (barMaxLength - barLength); if (barGrowingFromFront) barExtraL
19、ength = distance * destLength; else float newLength = destLength * (1 - distance); mProgress += (barExtraLength - newLength); barExtraLength = newLength; else pausedTimeWithoutGrowing += deltaTimeInMilliSeconds; pausedTimeWithoutGrowing < pauseGrowingTime显而易见 pausedTimeWithoutGrowing 作为 圆弧在 最大/最小
20、 角度保持的时间,初始状态下默认值是 0,那么代码逻辑走入 else: pausedTimeWithoutGrowing += deltaTimeInMilliSeconds。调用了 updateBarLength,应该说现在圆弧还处在角度保持不变的状态下,但是 圆弧的起始绘制角度 却一刻不能停:/ spinSpeed 作为每秒转过的角度,作为每秒的角度速度,用当前的时间差 deltaTime 计算,在这段时间里面转过了多少角度float deltaNormalized = deltaTime * spinSpeed / 1000.0f;/ mProgress 永远处于递增的状态mProgre
21、ss += deltaNormalized;/ 当 mProgress 超过 360 即超过一圈,那么减去一圈的角度 360。另外当超过一圈的时机,会给回调函数传入一个特殊的值 -1,至于回调函数的具体处理逻辑,这个就看项目需求了。if (mProgress > 360) mProgress -= 360f; / A full turn has been completed / we run the callback with -1 in case we want to / do ing, like changing the color runCallback(-1.0f); /更新 l
22、astTimeAnimated 上次绘制时间lastTimeAnimated = SystemClock.uptimeMillis();/ 其实这一步刚刚开始看得有点迷惑性,后来一想,圆弧的 0 度起始点其实是从 右半水平半径开始的, 减去 90 度后,就会从圆的顶点开始。float from = mProgress - 90;/ barExtraLength 在这个时段 barExtraLength 并没有被赋值那么,length 的值一直都是 16float length = barLength + barExtraLength;/ isInEditMode 这个其实是为了修饰的代码,如果
23、你添加在了 xml里面,那么圆弧的默认显示状态就是 0 - 135。这个没什么好说的if (isInEditMode() from = 0; length = 135;/ 最后一步绘制canvas.drawArc(circleBounds, from, length, false, barPaint);那么以上的分析和注释都是在 pausedTimeWithoutGrowing < pauseGrowingTime 的状态下,源码中 pauseGrowingTime = 200也就是这个圆弧大小保持不变的状态会保持 200 毫秒左右,超过了这个限制,那么就要开始递增或者递减了。pause
24、dTimeWithoutGrowing >= pauseGrowingTime /timeStartGrowing从圆弧开始变化,记录下变化的总时间, timeStartGrowing += deltaTimeInMilliSeconds; /* * 这个判断可以先跳过,看完函数后面的代码,再来看,我感觉会清晰点,当然如果你能理解,那就直接看 * barSpinCycleTime 作为 递增/递减 规定的变化总是时间, * 当 timeStartGrowing 大于这个时间时,说明圆弧的下一个变化就需要有所改变了 * 所谓的改变就是 递增 -> 递减 或者 递减 -> 递增
25、* 这个改变的标记通过 改变 barGrowingFromFront 来实现 !barGrowingFromFront。 * 于此同是将相关参数重新初始化 pausedTimeWithoutGrowing * pausedTimeWithoutGrowing = 0,保证了最大/最小状态下 圆弧不会瞬间改变,而是有一个旋转并保持的过程 * 并且为了精确计算圆弧的长度,还需要计算 timeStartGrowing -= barSpinCycleTime * timeStartGrowing:源码中 barSpinCycleTime 为 460ms,如果 timeStartGrowing = 48
26、0ms,也就是说 圆弧的角度不应该是 16,而应该是 16 + (480 - 460)这段时间差对应的额外的角度 * */ if (timeStartGrowing > barSpinCycleTime) / We completed a size change cycle / (growing or inking) timeStartGrowing -= barSpinCycleTime; /if(barGrowingFromFront) pausedTimeWithoutGrowing = 0; / barGrowingFromFront = !barGrowingFromFront
27、; /* * 在准备的环节,已经介绍过了,这是开始与结束慢,中间加速的函数 * timeStartGrowing / barSpinCycleTime 其实就是计算当前变化的总时间,占规定变化时间上限的比列 * 其实我做过实验,即便写成 float distance = timeStartGrowing / barSpinCycleTime;如果你不是拥有像素眼,那么基本是看不出来的,毕竟整个变化时间才 460ms,更不要说 中间那段加速的时间了. */ float distance = (float) Math.cos(timeStartGrowing / barSpinCycleTime
28、+ 1) * Math.PI) / 2 + 0.5f; /* *如果不考虑自己重新订制圆弧的最大角度和最小角度,那么 destLength 其实是个常数, *这种只需要进行一次的计算,我建议可以直接在 onSizeChanged 里面做,而不用每次都计算一次,个人优化建议 * destLength 代表着 额外需要绘制的角度 barExtraLength 的最大值 */ float destLength = (barMaxLength - barLength); if (barGrowingFromFront) /* * barGrowingFromFront 的默认值就是 true,也就是默认情况下是递增的 * 之前的分析已经说过了 float length = barLength + barExtraLength,绘制的角度,其实就是 最小角度 + 额外需要绘制的角度。 * barExtraLength = 时间(其实也可以理解为角度)的百分比 * barExtraLength 的最大值,这样就可以得出 额
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026上半年四川成都市大邑县医疗卫生事业单位考核招聘高层次人才23人备考题库及答案详解【新】
- 2026浙江宁波能源集团股份有限公司第一批招聘20人备考题库【必刷】附答案详解
- 2026山东省新动能基金管理有限公司校园招聘8人备考题库带答案详解(b卷)
- 2026中国电信量子公司春季博士招聘备考题库及答案详解【名师系列】
- 2026广东省佛山南海区桂城中学面向毕业生公招聘编制教师3人备考题库附答案详解【培优a卷】
- 2026中国资源循环集团有限公司春季校园招聘备考题库及参考答案详解(轻巧夺冠)
- 2026河北沧州任丘关爱精神病医院招聘备考题库及答案详解(新)
- 2026新疆和田墨玉县鑫玉经济开发有限责任公司招聘8人备考题库带答案详解(轻巧夺冠)
- 【基于网络学习的故障诊断方法研究国内外文献综述5000字】
- 2025-2030中国左旋肉碱(L-CARNITINE)市场产销销售渠道及经营效益分析研究报告
- 清明假期安全教育课件
- 兴国经济开发区投资开发有限公司2026年公开招聘笔试参考试题及答案解析
- 2026年循证护理计划
- 机电工程创优指南
- 体验营销外文文献翻译2025年译文3000多字
- 2026年民族团结测试题题库及答案
- 某律所财务内部管理制度
- 园长幼儿园考核制度
- 2025宁夏德润农业发展投资集团有限公司招聘合格人员及笔试历年备考题库附带答案详解
- 学校文印室财务制度
- 2026年河北公路养护高级技师试题及答案
评论
0/150
提交评论