依然是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; @Override
public int getSize(Paint paint, CharSequence text, int start, int end, FontMetricsInt fontMetricsInt) {
return (int) paint.measureText(text, start, end);
} @Override
public 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() { @Override
public 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;
//一旦開始就INFINITE
setAllAnimationsRepeatCount(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。

使用SpannableString实现一个load小动画的更多相关文章

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

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

  2. 利用@keyframe及animation做一个页面Loading时的小动画

    前言 利用@keyframe规则和animation常用属性做一个页面Loading时的小动画. 1  @keyframe规则简介 @keyframes定义关键帧,即动画每一帧执行什么. 要使用关键帧 ...

  3. 微信小程序循环列表点击每一个单独添加动画

    首先,咱们看一下微信小程序动画怎么实现,我首先想到的是anime.js,但是引入之后用不了,微信小程序内的css也无法做到循环的动态,我就去找官方文档看看有没有相应的方法,哎,还真有 点击这里查看 微 ...

  4. CSS3-实现单选框radio的小动画

    在微信上看到一个教程文,觉得制作的小动画还是很有意思的,自己也试验了一下.一开始动画怎么都不执行(我用的HB),因为内置浏览器对css3的不兼容.加上各种浏览器前缀后就好了.但是旋转那个效果,在HB里 ...

  5. WPF之小动画一

    定义动画: 直接使用Element进行BeginAnimation DoubleAnimation animation = new DoubleAnimation(); animation.By = ...

  6. 如何制作网页小动画?——gif or png

    一.场景与动画 为了拉动网站氛围,或者吸引用户浏览焦点,需要使用一些小动画.这种动画不是(gif)单纯的重复,而是需要需要一些控制和交互,比如在动画完成后打开一个对话框.动画有几个基本要素(时间控制, ...

  7. 一个Hibernate小程序

    基本步骤 在前一篇博文Hibernate环境搭建中为大家详细的介绍如何搭建一个学习新类库的学习环境.今天,为大家带来一个Hibernate小例子,让大家能够快速上手. 步骤如下: 1.配置hibern ...

  8. 利用jQuery实现用户名片小动画

    我爱撸码,撸码使我感到快乐!大家好,我是Counter.下面给大家介绍利用jQuery实现的小动画,非常的简便,如果有原生js操作的话,那么就不止这么多行了.至于CSS,个人觉得,这边CSS布局也蛮重 ...

  9. 前端动画小记---bilibili ( ゜-゜)つロ客户下载小动画

    逛哔哩哔哩 ( ゜-゜)つロPC版的时候看到一个蛮有意思的动画,指导用户去下载客户端,于是摸索实现了一个. 原动画效果 可以看到,一个静止的小电视人,当鼠标移动到电视人身上时,电视人慢慢变身成为一个小 ...

随机推荐

  1. 洛谷——P1614 爱与愁的心痛

    题目背景 (本道题目隐藏了两首歌名,找找看哪~~~) <爱与愁的故事第一弹·heartache>第一章 <我为歌狂>当中伍思凯神曲<舞月光>居然没赢给萨顶顶,爱与愁 ...

  2. logstash filter plugin

    1. 基本语法%{NUMBER:duration} %{IP:client} 2. 支持的数据类型默认会把所有的匹配都当作字符串,比如0.043, 想要转成浮点数,可以%{NUMBER:num:flo ...

  3. Web/JAVA 简单题目汇总

    [Java标识符,变量.常量] 一.Java合法标识符命名规则 (1)区分字母大小写,标识符长度不限 (2)  英文,Unicode码双字节文字字符(日文,韩文,中文),数字,下划线,$(美元符号)均 ...

  4. luogu P1122 最大子树和

    题目描述 小明对数学饱有兴趣,并且是个勤奋好学的学生,总是在课后留在教室向老师请教一些问题.一天他早晨骑车去上课,路上见到一个老伯正在修剪花花草草,顿时想到了一个有关修剪花卉的问题.于是当日课后,小明 ...

  5. [POI2014]Ant colony

    题目大意: 给定一棵$n(n\le10^6)$个结点的树.在每个叶子结点,有$g$群蚂蚁要从外面进来,其中第$i$群有$m_i$只蚂蚁.这些蚂蚁依次爬树(一群蚂蚁爬完后才会爬另一群),若当前经过结点度 ...

  6. 七. 多线程编程6.isAlive()和join()的使用

    如前所述,通常你希望主线程最后结束.在前面的例子中,这点是通过在main()中调用sleep()来实现的,经过足够长时间的延迟以确保所有子线程都先于主线程结束.然而,这不是一个令人满意的解决方法,它也 ...

  7. 快速创建一个的指定大小的内容全为0xFF的文件

    比如需要创建一个大小为2KB,内容为全0xFF的文件 步骤只有两步: 第一步. dd if=/dev/zero of=./test.img bs=1 count=2048 第二步. 使用WinHex文 ...

  8. 【spring boot】14.spring boot集成mybatis,注解方式OR映射文件方式AND pagehelper分页插件【Mybatis】pagehelper分页插件分页查询无效解决方法

    spring boot集成mybatis,集成使用mybatis拖沓了好久,今天终于可以补起来了. 本篇源码中,同时使用了Spring data JPA 和 Mybatis两种方式. 在使用的过程中一 ...

  9. Quartz配置CronTrigger

    CronTrigger 构造器 String name, //触发器名称 String group, //触发器的组名 String jobName, //job名称 String jobGroup, ...

  10. cornerstone

    这东西是mac上的svn,忽然就不对劲了.感觉就是代码就是没拿对.里面显示都是正确的. 删了重新拿....