依然是github开源项目:WaitingDots
这个项目代码不多,实现的非常easy。可是非常有意思由于动画的基本元素不是画出来的,而是使用了spannableString来实现。

  • DotsTextView.java
  • JumpingSpan.java
  • MainActivity.java
    DotstextView是动画的实现主体。
    JumpingSpan是基本元素,是动画中的插件
    MainActivity中仅仅要在布局中引入DotsTextView就可以。
    下面是切割线,show code:
package pl.tajchert.sample;import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.FontMetricsInt;
import android.text.style.ReplacementSpan;
/* ReplacementSpan真是一个挺奇妙的东西。在官方api上介绍甚少*几个主要功能函数也是do nothing.* 本例中自己定义的translationX,translationY没有发挥作用。假设给两个变量赋值* 那么第一个JumpingSpan距离前面元素距离增大,这里这样使用是为了让每一个"."为一个单独的单元进行独立操作*/
public class JumpingSpan extends ReplacementSpan {private float translationX = 0;private float translationY = 0;@Overridepublic int getSize(Paint paint, CharSequence text, int start, int end, FontMetricsInt fontMetricsInt) {return (int) paint.measureText(text, start, end);}@Overridepublic void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint) {canvas.drawText(text, start, end, x + translationX, y + translationY, paint);}public void setTranslationX(float translationX) {this.translationX = translationX;}public void setTranslationY(float translationY) {this.translationY = translationY;}
}
package pl.tajchert.sample;import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.TypeEvaluator;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Handler;
import android.os.Looper;
import android.text.SpannableString;
import android.text.Spanned;
import android.util.AttributeSet;
import android.widget.TextView;import pl.tajchert.waitingdots.R;public class DotsTextView extends TextView {private JumpingSpan dotOne;private JumpingSpan dotTwo;private JumpingSpan dotThree;private int showSpeed = 700;private int jumpHeight;private boolean autoPlay;private boolean isPlaying;private boolean isHide;private int period;private long startTime;private boolean lockDotOne;private boolean lockDotTwo;private boolean lockDotThree;private Handler handler;private AnimatorSet mAnimatorSet = new AnimatorSet();private float textWidth;public DotsTextView(Context context) {super(context);init(context, null);}public DotsTextView(Context context, AttributeSet attrs) {super(context, attrs);init(context, attrs);}public DotsTextView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init(context, attrs);}private void init(Context context, AttributeSet attrs) {handler = new Handler(Looper.getMainLooper());//自己定义属性if (attrs != null) {TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.WaitingDots);period = typedArray.getInt(R.styleable.WaitingDots_period, 6000);jumpHeight = typedArray.getInt(R.styleable.WaitingDots_jumpHeight, (int) (getTextSize() / 4));autoPlay = typedArray.getBoolean(R.styleable.WaitingDots_autoplay, true);typedArray.recycle();}dotOne = new JumpingSpan();dotTwo = new JumpingSpan();dotThree = new JumpingSpan();//将每一个点设置为jumpingSpan类型SpannableString spannable = new SpannableString("...");spannable.setSpan(dotOne, 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);spannable.setSpan(dotTwo, 1, 2, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);spannable.setSpan(dotThree, 2, 3, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);setText(spannable, BufferType.SPANNABLE);textWidth = getPaint().measureText(".", 0, 1);//一下两个是把updateListener加到点1上,通过它来进行刷新动作ObjectAnimator dotOneJumpAnimator = createDotJumpAnimator(dotOne, 0);dotOneJumpAnimator.addUpdateListener(new AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator valueAnimator) {invalidate();}});//这里通过animationSet来控制三个点的组合动作mAnimatorSet.playTogether(dotOneJumpAnimator, createDotJumpAnimator(dotTwo,period / 6), createDotJumpAnimator(dotThree, period * 2 / 6));isPlaying = autoPlay;if(autoPlay) {start();}}public void start() {isPlaying = true;//一旦開始就INFINITEsetAllAnimationsRepeatCount(ValueAnimator.INFINITE);mAnimatorSet.start();}/*动画的实现核心*@param jumpingSpan 传入点。* @delay 动画执行延迟,通过这个參数让三个点进行有时差的运动*/private ObjectAnimator createDotJumpAnimator(JumpingSpan jumpingSpan, long delay) {ObjectAnimator jumpAnimator = ObjectAnimator.ofFloat(jumpingSpan, "translationY", 0, -jumpHeight);/*setEvaluator这个重要。功能是为了通过方程来平滑的实现点运动的“节奏感”,能够试试把这段去掉。你会发现点会以默认的速度上下运动,特别生硬。TypeEvaluator中的evaluate能够计算出点的当前位置。通过对当前点的计算间接设计了点的轨迹运动,和时间插值TimeInterpolator达到同样的效果。就好比你不知道速度可是你知道每秒所在的位置相当于速度了。

这个计算方法是这种:能够參见这个博文 http://blog.csdn.net/serapme/article/details/47006049 ValueAnimator还封装了一个TypeAnimator。依据開始、结束值与TimeIniterpolator计算得到的值计算出属性值。 ValueAnimator依据动画已进行的时间跟动画总时间(duration)的比计算出一个时间因子(0~1),然后依据TimeInterpolator计算出还有一个因子,最后TypeAnimator通过这个因子计算出属性值,如上例中10ms时: 首先计算出时间因子,即经过的时间百分比:t=10ms/40ms=0.25 经插值计算(inteplator)后的插值因子:大约为0.15。上述样例中用了AccelerateDecelerateInterpolator,计算公式为(input即为时间因子): (Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f; 最后依据TypeEvaluator计算出在10ms时的属性值:0.15*(40-0)=6pixel。上例中TypeEvaluator为FloatEvaluator,计算方法为 : public Float evaluate(float fraction, Number startValue, Number endValue) { float startFloat = startValue.floatValue(); return startFloat + fraction * (endValue.floatValue() - startFloat); } */

jumpAnimator.setEvaluator(new TypeEvaluator<Number>() { @Override public Number evaluate(float fraction, Number from, Number to) { return Math.max(0, Math.sin(fraction * Math.PI * 2)) * (to.floatValue() - from.floatValue()); } }); jumpAnimator.setDuration(period); jumpAnimator.setStartDelay(delay); jumpAnimator.setRepeatCount(ValueAnimator.INFINITE); jumpAnimator.setRepeatMode(ValueAnimator.RESTART); return jumpAnimator; } //下面部分非核心功能也没难度就不凝视了~主要是由于懒~ public void stop() { isPlaying = false; setAllAnimationsRepeatCount(0); } private void setAllAnimationsRepeatCount(int repeatCount) { for (Animator animator : mAnimatorSet.getChildAnimations()) { if (animator instanceof ObjectAnimator) { ((ObjectAnimator) animator).setRepeatCount(repeatCount); } } } public void hide() { createDotHideAnimator(dotThree, 2).start(); ObjectAnimator dotTwoMoveRightToLeft = createDotHideAnimator(dotTwo, 1); dotTwoMoveRightToLeft.addUpdateListener(new AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { invalidate(); } }); dotTwoMoveRightToLeft.start(); isHide = true; } public void show() { ObjectAnimator dotThreeMoveRightToLeft = createDotShowAnimator(dotThree, 2); dotThreeMoveRightToLeft.start(); ObjectAnimator dotTwoMoveRightToLeft = createDotShowAnimator(dotTwo, 1); dotTwoMoveRightToLeft.addUpdateListener(new AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { invalidate(); } }); dotTwoMoveRightToLeft.start(); isHide = false; } private ObjectAnimator createDotHideAnimator(JumpingSpan span, float widthMultiplier) { return createDotHorizontalAnimator(span, 0, -textWidth * widthMultiplier); } private ObjectAnimator createDotShowAnimator(JumpingSpan span, int widthMultiplier) { return createDotHorizontalAnimator(span, -textWidth * widthMultiplier, 0); } private ObjectAnimator createDotHorizontalAnimator(JumpingSpan span, float from, float to) { ObjectAnimator dotThreeMoveRightToLeft = ObjectAnimator.ofFloat(span, "translationX", from, to); dotThreeMoveRightToLeft.setDuration(showSpeed); return dotThreeMoveRightToLeft; } public void showAndPlay() { show(); start(); } public void hideAndStop() { hide(); stop(); } public boolean isHide() { return isHide; } public boolean isPlaying() { return isPlaying; } public void setJumpHeight(int jumpHeight) { this.jumpHeight = jumpHeight; } public void setPeriod(int period) { this.period = period; } }

毫无疑问在activity中引入布局中就可以。

dotsTextView = (DotsTextView) findViewById(R.id.dots);

一个简单使用的loadingview。

转载于:https://www.cnblogs.com/wzjhoutai/p/7249613.html

使用SpannableString实现一个load小动画相关推荐

  1. 用 Rust 写一个声控小动画

    某一天,朋友发给我这样一张图: 这张图片原本的目的是用于介绍一种深度学习算法,这种算法能够识别不同角度的长条形物体.这张图片用来表示识别时所用到的先验框. 虽然图形本身的绘制原理比较简单,但很适合作为 ...

  2. 前端开发,用 css3 做一个求婚小动画

    首先放张效果图 然后一步步分析一下 首先是刚出现的新郎的动画 .w-m img{ margin-right: 0; float: right; margin-top: 60px; animation: ...

  3. 用css3做一个求婚小动画

    概述 本案例主要是运用到了css3的animation.keyframes.transform等属性,熟悉了,就可以做更多的其他动画效果,这几个属性功能非常强大. 详细 代码下载:http://www ...

  4. 前端搞一个扭蛋抽奖小动画?

    最近新增一个抽奖小模块,就是扭蛋机的形式,产品给了参考网页,奈何不好扒下来用,只得自己动手干了,不多bb,先看效果吧! 效果图: 动画分析 由上面gif可看出,整个动画分为四个部分 扭蛋随机(也不算随 ...

  5. 运用计算机来动画制作的视频,如何制作一个时钟转动动画视频?电脑制作动画的软件制作时钟转动的小视频的方法...

    今天小编要来介绍的是制作动画的软件,可以用于制作时钟转动的动画效果,之前小编就介绍过时钟动画制作的方法,但今天的方法更先进哦,这里的时钟的样式还有颜色都可以自定义的哦.制作动画的软件是什么?不是手机自 ...

  6. 设计-来做一个Windows hello的小动画

    今天想和大家分享的是一个Windows hello的动画,也就是这个笑脸的效果. 当时是因为一个小伙伴在交流群里问了一下这个效果是怎么制作的,我觉得还挺有意思的,就觉得复刻一下,顺便出一期教程来讲讲其 ...

  7. PR教程:1分钟制作一个简约文字小动画视频开场片头

    PR教程:1分钟制作一个简约文字小动画视频开场片头 微信公众号:知音后期,一个简单直接分享干货的公众号!

  8. 用p5.js实现一个小动画——故宫橘猫赏秋图

    用p5.js实现一个小动画--故宫橘猫赏秋图 互动媒体第二次作业要求我们手绘一幅动画,再用代码实现出动画.由于时间原因,手绘并没有画动画,而是以插画的形式画了一张,然后p5实现了动画. 这里先放效果图 ...

  9. 计算机动画制作简单动画视频教程,如何制作一个时钟转动动画视频?电脑制作动画的软件制作时钟转动的小视频的方法...

    今天小编要来介绍的是制作动画的软件,可以用于制作时钟转动的动画效果,之前小编就介绍过时钟动画制作的方法,但今天的方法更先进哦,这里的时钟的样式还有颜色都可以自定义的哦.制作动画的软件是什么?不是手机自 ...

最新文章

  1. PHP用foreach来表达array_walk/array_filter/array_map/array_reduce
  2. ADO.NET与ADO
  3. 使用API动态添加删除菜单项
  4. HTML JAVASCRIPT CSS 大小写敏感问题
  5. 事件驱动之JDK观察者模式
  6. ASP.NET获取客户端、服务器端基础信息
  7. C#中的Dictionary字典类介绍(转载)
  8. Centos系统镜像下载
  9. 及时复盘的好处_复盘,组织和个人提升的一种特效工具
  10. Kubernetes学习总结(1)——Kubernetes入门简介
  11. NYOJ--975--关于521
  12. SVProgressHUD的使用
  13. 百乐达斯城全新梦幻主题乐园幻乐堡在韩国开业
  14. OSChina 周一乱弹 ——女人比代码复杂多了,搞不懂!
  15. 基于eNSP华为模拟器的VRRP简单实验
  16. #define宏的妙用!实现你以为的函数offsetof等
  17. dwz ajax提交,DWZ-JUI Ajax.post 封装
  18. citus多CN部署
  19. 如何实现修改c语言题库,编程培训 所有C语言题库(修改后).docx
  20. Elastic Search创建文档和更新文档

热门文章

  1. 计算机专业可报机电一体化吗,文科生可以报考机电一体化技术专业吗
  2. 小白兔白又白如何用python转换成小了白了兔白了又了白
  3. 改进的RANSAC算法实现点云粗配准
  4. 求购运用于苹果操作系统的电子白板软件!!急!!
  5. win10怎么显示文件后缀_U盘数据丢失怎么恢复?数据恢复软件推荐
  6. XDS100V3-DIY
  7. P2300 合并神犇(单调队列优化dp)
  8. html css 扑克牌桌面,CSS Card:纯css制作扑克牌_html/css_WEB-ITnose
  9. 股票市场什么叫除权,股票除权会有什么影响
  10. MATLAB中imfill()函数解释