关键词:
依然是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实现textview的链接效果
SpannableString实现TextView的链接效果一、简介TextView使用SpannableString设置复合文本TextView通常用来显示普通文本,但是有时候需要对其中某些文本进行样式、事件方面的设置。Android系统通过SpannableString类来对指定文本进行相关处理... 查看详情
android中实现特殊符号㎡的显示使用spannablestring类来实现(代码片段)
前言:SpannableString的介绍SpannableString,是CharSequence的一种,原本的CharSequence只是一串字符序列,没有任何样式,而SpannableString可以在字符序列基础上对指定的字符进行润饰,在开发中,TextView可以通过se... 查看详情
android中使用spannablestring实现textview文本超链接跳转功能(代码片段)
...策”时可以跳转到相应的说明页面。这个时候就需要用到SpannableString富文本,实现点击文本跳转的功能。SpannableString可以通过使用setSpan方 查看详情
使用 SpannableString 调整文本对齐方式
】使用SpannableString调整文本对齐方式【英文标题】:AdjustingtextalignmentusingSpannableString【发布时间】:2012-02-1723:33:18【问题描述】:我创建了一个SpannableString,第一个字符,最后两个小于其余字符。它看起来像这样:sBBBBss我想对... 查看详情
spannablestring与spannablestringbuilder使用
转自:http://blog.it985.com/14433.html1、SpannableString、SpannableStringBuilder与String的关系首先SpannableString、SpannableStringBuilder基本上与String差不多,也是用来存储字符串,但它们俩的特殊就在于有一个SetSpan()函数,能给这些存储的String添... 查看详情
spannablestring与spannablestringbuilder使用
1、SpannableString、SpannableStringBuilder与String的关系首先SpannableString、SpannableStringBuilder基本上与String差不多,也是用来存储字符串,但它们俩的特殊就在于有一个SetSpan()函数,能给这些存储的String添加各种格式或者称样式(Span)... 查看详情
SpannableString 可以序列化吗?
】SpannableString可以序列化吗?【英文标题】:CanSpannableStringbeSerializable?【发布时间】:2017-08-2318:26:36【问题描述】:我想通过Intent发布一个带有SpannableString的对象。我让对象实现Serializable,但它会抛出java.io.NotSerializableException:and... 查看详情
java一个辅助类,用于构造和修改使用factory设计模式的spannablestring(代码片段)
使用 spannableString 在 android 中更改 TextView 文本的颜色
】使用spannableString在android中更改TextView文本的颜色【英文标题】:ChangingColorOfTextViewtextinandroidusingspannableString【发布时间】:2016-09-0222:22:31【问题描述】:我有一个字符串1Friend|OReviews|0Coupons我正在使用以下代码SpannableStringhashText=... 查看详情
spannablestring重复使用在textview里的排版问题自动换行
Androidtextview,当使用SpannableString设置字体append到textview后自动换行就把界面搞乱,特别是一个字使用多个SpannableString的时候,比如同时加粗和下划线,就不满一行就换行。textview是重写的,ondraw()没有重写,找不到解决办法。求高... 查看详情
[react]使用高阶组件(hoc)实现一个loading组件(代码片段)
[react]使用高阶组件(HOC)实现一个loading组件functionHOC(wrappedComponent)returnclassextendsReact.Componentrender()if(!this.props.data)return(<div>loading</div>)return<wrappedComponent...this.props/> 个人简介我是歌谣,欢迎和大家一起交流前后端... 查看详情
androidtextview结合spannablestring使用大全
protectedvoidonCreate(BundlesavedInstanceState)super.onCreate(savedInstanceState);setContentView(R.layout.textview);TextViewtxtInfo=(TextView)findViewById(R.id.tv);//SpannableString文本类,包含不可 查看详情
从 SpannableStringBuilder 获取 SpannableString 的最佳方法
】从SpannableStringBuilder获取SpannableString的最佳方法【英文标题】:BestwaytogetaSpannableStringfromaSpannableStringBuilder【发布时间】:2014-06-0411:55:54【问题描述】:我正在使用一个类似于wiki的解析器,它为一组标记标记创建跨度。它正在工... 查看详情
-textview使用spannablestring设置复合文本
...中某些文本进行样式、事件方面的设置。Android系统通过SpannableString类来对指定文本进行相关处理,具体有以下功能:1、BackgroundColorSpan背景色 2、ClickableSpan文本可点击,有点击事件3、ForegroundColorSpan文本颜色(前景色)4、Mask... 查看详情
将textview转换为spannablestring(代码片段)
我有一个用户正在选择关键字的屏幕,然后该关键字在SpannableString完成的句子内的下一个屏幕中突出显示。我想要的是在SpannableString中将选定的关键字设置为动画。是否有可能在TextView的文本中为SpannableString的文本制作动画?答... 查看详情
textview使用spannablestring设置复合文本(转)
...中某些文本进行样式、事件方面的设置。Android系统通过SpannableString类来对指定文本进行相关处理,具体有以下功能:1、BackgroundColorSpan背景色 2、ClickableSpan文本可点击,有点击事件3、ForegroundColorSpan文本颜色(前景色)4、Mask... 查看详情
java示例代码_在android中使用带正则表达式的SpannableString
java示例代码_在android中使用带正则表达式的SpannableString 查看详情
自动适应 TextView 和 spannableString
】自动适应TextView和spannableString【英文标题】:auto-fitTextViewandspannableString【发布时间】:2018-07-1305:55:36【问题描述】:背景我需要使用SpannableString在textView中显示金额,然后将TextView的字体调整到给定的边界,如下所示:SpannableSt... 查看详情