核心思想就是在自定义View中重写Animation中的applyTransformation方法,在其中使用postInvalidate()方法刷新界面,调用onDraw()来实现数字变化。
以下是代码与注释:
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.Transformation;
/**
* 使用内部的Animation驱动View的onDraw使数字滚动
* @author WeiTao
*
*/
public class RuningNumView extends View{
//这里的digit表示的是位数,就是个十百千,因为项目需要所以加上的
private int count, digit;
private String text;
private MyAnimation anim;
private Paint textPaint;
private int textSize;
private RectF frameRectangle = new RectF();
public RuningNumView(Context context) {
super(context);
init();
}
public RuningNumView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public RuningNumView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public void init(){
text = "0";
anim = new MyAnimation();
final float scale = getContext().getResources().getDisplayMetrics().density;
textSize = (int) (33 * scale + 0.5f);
textPaint = new Paint(Paint.ANTI_ALIAS_FLAG|Paint.LINEAR_TEXT_FLAG);
textPaint.setColor(0xFFFFFFFF);
textPaint.setStyle(Style.FILL_AND_STROKE);
textPaint.setTextSize(textSize);
}
@SuppressLint("DrawAllocation") @Override
protected void onDraw(Canvas canvas){
//处理下要显示出来的数字,这里是为了获得个十百位中的一位
String textStr = (count % (int)Math.pow(10,digit))/(int)Math.pow(10,digit-1) + "";
Rect bounds = new Rect();
textPaint.getTextBounds(textStr, 0, textStr.length(), bounds);
//画出数字
canvas.drawText(textStr,
frameRectangle.centerX() - (textPaint.measureText(textStr) / 2),
frameRectangle.centerY() + bounds.height() / 2,
textPaint);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int height = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
int width = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
int min = Math.min(width, height);
setMeasuredDimension(min, min);
frameRectangle.set(0, 0, min, min);
}
/**
*
* @param text 最终数字
* @param digit 要显示的数位(1/2/3)
*/
public RuningNumView setTextAndDigit(String text, int digit){
this.text = text;
this.digit = digit;
return this;
}
public RuningNumView setDuration(long durationMillis){
anim.setDuration(durationMillis);
return this;
}
public void startAnimation(){
this.startAnimation(anim);
}
public class MyAnimation extends Animation{
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
super.applyTransformation(interpolatedTime, t);
if(interpolatedTime < 1.0f){
//随着动画播放,interpolatedTime会由0变化到1,通过它,我们可以获取变化中的数字(乘以下总数就行了)
count = (int)(interpolatedTime * Float.parseFloat(text));
}else{
count = Integer.parseInt(text);
}
postInvalidate();//调用onDraw()
}
}
}
变量设置:
RuningNumView tx_num1, tx_num2, tx_num3;
String score = "750";
以下依次是百位、十位、个位,两秒的动画,同时执行:
tx_num1.setDuration(2000).setTextAndDigit(score, 3);
tx_num2.setDuration(2000).setTextAndDigit(score, 2);
tx_num3.setDuration(2000).setTextAndDigit(score, 1);
tx_num1.startAnimation();
tx_num2.startAnimation();
tx_num3.startAnimation();
这里外部用的是LinearLayout布局:
<com.taotaojin.view.RuningNumView
android:id="@+id/tx_num1"
android:layout_width="45dp"
android:layout_height="55dp"/>
<com.taotaojin.view.RuningNumView
android:id="@+id/tx_num2"
android:layout_width="45dp"
android:layout_height="55dp" />
<com.taotaojin.view.RuningNumView
android:id="@+id/tx_num3"
android:layout_width="45dp"
android:layout_height="55dp"/>
当然,也可以写成一个View就显示完整数字,我把它们拆分开完全是因为项目需要。