Android 开发之轻量级文本动画
2017-04-11 本文已影响51人
凡凡此种种
Android 开发之轻量级文本动画
转载请注明出处 传送门 本文出自【付小华的博客】
引言
在掘金上看到推文,用JS实现了文字动画和数字动画 animate text,效果如下:
自己就在Android端简单粗暴地模仿了一个,具体实现就是handler,random,效果如下:
使用
<xxxxxxxx.widget.AnimateText
android:id="@+id/animationText1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="50dp"
android:lines="10"
android:text="\u3000\u3000寄居在桂子山叔叔家中,不觉已是两个多月了,居室的环境极为情幽静谧,古朴自然之中又透着一种雅致。特别是那满山的木樨,中秋一过,便黄灿灿地开满枝头,悠悠的香气随风飘送。昨夜,西风渐紧,刮得楼下梧桐树“沙沙”地响,躺在床上,心想,明晨,又该是花落知多少了!今早推门一看,湿湿的水泥小径上,满是枯枝败叶,再细看枝叶间,黄灿灿的一片,竟是桂花!不由得脱口而出一句诗来:昨夜西风过园林,吹落黄花满地金!不禁心头一动,眼前幻化出父亲的影子来。"
android:textColor="@color/colorPrimary"
android:textSize="16sp" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:onClick="animation1"
android:text="重新播放" />
<xxxxxxxx.widget.AnimateText
android:id="@+id/animationText2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="50dp"
android:text="666666.66"
android:textColor="@color/colorPrimary"
android:textSize="25sp"
app:changeCount="50"
app:isNumber="true" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:onClick="animation2"
android:text="重新播放" />
代码
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Handler;
import android.os.Looper;
import android.support.annotation.Nullable;
import android.support.v7.widget.AppCompatTextView;
import android.util.AttributeSet;
import com.shenhua.newscachedemo.R;
import java.util.Random;
/**
* Created by shenhua on 4/11/2017.
* Email shenhuanet@126.com
*/
public class AnimateText extends AppCompatTextView {
private Handler handler = new Handler(Looper.getMainLooper());
private boolean annimaStart = false; // 开始时是否展示动画
private boolean isNumber = false; // 是否渲染为数字动画
private int time = 20;// 动画时长
private int changeCount = 32; // 数字动画数字变化次数
private int startNumber = 0; // 渲染为数字动画时 动画的开始数字
private int endNumber = 0; // 渲染为数字动画时 动画的结束数字
private OnAnimationEndListener listener;// 动画结束时的监听
private String text;// 文本
public AnimateText(Context context) {
this(context, null);
}
public AnimateText(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public AnimateText(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
if (attrs != null) {
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AnimateText);
annimaStart = a.getBoolean(R.styleable.AnimateText_annimaStart, false);
isNumber = a.getBoolean(R.styleable.AnimateText_isNumber, false);
time = a.getInteger(R.styleable.AnimateText_time, 20);
changeCount = a.getInteger(R.styleable.AnimateText_changeCount, 32);
a.recycle();
}
text = getText().toString();
if (isNumber) {
startNumber = text.length() - 1;
endNumber = (int) Float.parseFloat(text);
}
if (annimaStart) {
startAnimate();
}
}
public void startAnimate() {
this.startAnimate(null);
}
public void startAnimate(final OnAnimationEndListener listener) {
this.listener = listener;
new Thread(new Runnable() {
@Override
public void run() {
if (isNumber) {
showNumAnimate();
} else {
showNormalAnimate();
}
}
}).start();
}
private void showNormalAnimate() {
char[] cs = text.toCharArray();
final StringBuffer buffer = new StringBuffer();
for (char c : cs) {
buffer.append(c);
try {
Thread.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
handler.post(new Runnable() {
@Override
public void run() {
AnimateText.this.setText(buffer.toString(), BufferType.NORMAL);
}
});
}
handler.post(new Runnable() {
@Override
public void run() {
if (listener != null) {
listener.onEnd();
}
}
});
}
private void showNumAnimate() {
for (int i = 0; i < changeCount; i++) {
final float t = nextFloat();
try {
Thread.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
handler.post(new Runnable() {
@Override
public void run() {
setText(String.valueOf(t), BufferType.NORMAL);
}
});
}
handler.post(new Runnable() {
@Override
public void run() {
setText(text, BufferType.NORMAL);
}
});
}
private float nextFloat() {
return startNumber + ((endNumber - startNumber) * new Random().nextFloat());
}
public int getTime() {
return time;
}
public void setTime(int time) {
this.time = time;
}
public boolean isAnnimaStart() {
return annimaStart;
}
public void setAnnimaStart(boolean annimaStart) {
this.annimaStart = annimaStart;
}
public boolean isNumber() {
return isNumber;
}
public void setNumber(boolean number) {
isNumber = number;
}
public int getStartNumber() {
return startNumber;
}
public void setStartNumber(int startNumber) {
this.startNumber = startNumber;
}
public int getChangeCount() {
return changeCount;
}
public void setChangeCount(int changeCount) {
this.changeCount = changeCount;
}
public void setText(String text) {
this.text = text;
setText(text, BufferType.NORMAL);
}
public OnAnimationEndListener getListener() {
return listener;
}
public void setListener(OnAnimationEndListener listener) {
this.listener = listener;
}
public interface OnAnimationEndListener {
void onEnd();
}
}
- attr.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="AnimateText">
<attr name="time" format="integer" />
<attr name="annimaStart" format="boolean" />
<attr name="isNumber" format="boolean" />
<attr name="changeCount" format="integer" />
</declare-styleable>
</resources>
- 可使用的方法
setter 方法均可在外部调用,代码中已有详细说明。
好了,就这么多。