主要思想是用一个 Handler 不断地向UI主线程发消息,循环调用updateScore() -> invalidate() -> onDraw() 将百分数用画笔画在屏幕上。
使用示例:
1. 在你的main_layout.xml 文件中加入控件
<com.test.mytest.ScoreAnimationView
android:id="@+id/scan_progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="5dp"
android:layout_centerInParent="true"
android:text="0%" />
2. 在MainActivity.java 代码中调用代码
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_layout);
ScoreAnimationView progressScore = (ScoreAnimationView) findViewById(R.id.scan_progress);
progressScore.startScoreRollAnimation(0, 100);
}
3. ScoreAnimationView.java
package com.test.mytest;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.FontMetrics;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.View;
/**
* 百分数递增动态显示,可以用于progress显示
*/
public class ScoreAnimationView extends View {
/** 滚动开始的分数 **/
private int mFromScore = 0;
/** 滚动结束的分数 **/
private int mToScore = 0;
/** 是否开始绘制动画 **/
private boolean isDrawing = false;
/** 分数是否向上滚动 **/
private boolean isUp;
/**多添加两个字符,防止在不同字体时显示不全 */
private final String STRING = "100%__";
private int mViewWidth = 0;
private Paint mScorePaint;
private Context mContext;
private final int START_ANIMATION = 0;
/**
* Handler负责
*/
private Handler mHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case START_ANIMATION:
updateScore();
break;
}
};
};
public ScoreAnimationView(Context context) {
super(context);
mContext = context;
init();
}
public ScoreAnimationView(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
init();
}
/**
* 初始化画笔
*/
private void init() {
mScorePaint = new Paint();
mScorePaint.setColor(mContext.getResources().getColor(R.color.white));
mScorePaint.setTextSize(dip2px(mContext, 60));
mScorePaint.setAntiAlias(true);
}
/**
* 循环刷新页面,动态地将百分数从fromScore增长到toScore
* @param fromScore 起始百分数
* @param toScore 增长到的百分数
*/
public void startScoreRollAnimation(int fromScore, int toScore) {
if (fromScore > 0) {
mFromScore = fromScore > 100 ? 100 : fromScore;
} else {
mFromScore = 0;
}
if (toScore > 0) {
mToScore = toScore > 100 ? 100 : toScore;
} else {
mToScore = 0;
}
if ((mFromScore - mToScore) != 0) {
isDrawing = true;
if (mFromScore > mToScore) {
isUp = false;
} else {
isUp = true;
}
mHandler.sendEmptyMessage(START_ANIMATION);
} else {
isDrawing = true;
postInvalidate();
}
}
/**
* 最重要的函数,刷新页面,调用canvas.drawText()函数将百分数画在屏幕上
*/
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.TRANSPARENT);
int width = mViewWidth > 0 ? mViewWidth : dip2px(mContext, 150);
if (isDrawing) {
if (mFromScore < 10) {
canvas.drawText(String.valueOf(mFromScore) + "%", mViewWidth/3,
getStringHeight(mScorePaint), mScorePaint);
} else if (mFromScore < 100) {
canvas.drawText(String.valueOf(mFromScore) + "%", mViewWidth/4,
getStringHeight(mScorePaint), mScorePaint);
} else {
canvas.drawText(String.valueOf(mFromScore) + "%", mViewWidth/6, getStringHeight(mScorePaint),
mScorePaint);
}
} else {
if (mFromScore < 10) {
canvas.drawText(String.valueOf(mToScore) + "%", mViewWidth/3,
getStringHeight(mScorePaint), mScorePaint);
} else if (mToScore >= 100) {
canvas.drawText(String.valueOf(mToScore) + "%", mViewWidth/6, getStringHeight(mScorePaint),
mScorePaint);
} else {
canvas.drawText(String.valueOf(mToScore) + "%", mViewWidth/4,
getStringHeight(mScorePaint), mScorePaint);
}
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(getStringWidth(mScorePaint, STRING), getStringHeight(mScorePaint) + 20);
mViewWidth = this.getWidth();
}
/**
* 更新百分数,循环刷新页面的关键函数
*/
private void updateScore() {
if (isDrawing) {
if (isUp) {
mFromScore++;
if (mFromScore <= mToScore) {
invalidate();
mHandler.sendEmptyMessageDelayed(START_ANIMATION, 100);
} else {
mFromScore = mToScore;
}
} else {
mFromScore--;
if (mFromScore >= mToScore) {
invalidate();
mHandler.sendEmptyMessageDelayed(START_ANIMATION, 100);
} else {
mFromScore = mToScore;
}
}
}
}
public int getToScore() {
return mToScore;
}
public int getFromScore() {
return mFromScore;
}
public void setTextColor(int colorID) {
if (mScorePaint != null) {
mScorePaint.setColor(colorID);
}
invalidate();
}
/**
* 获取字符串宽度
*/
private int getStringWidth(Paint paint, String str) {
int strWidth = 0;
if (str != null && str.length() > 0) {
int length = str.length();
float[] widths = new float[length];
paint.getTextWidths(str, widths);
for (int k = 0; k < length; k++) {
strWidth += (int) Math.ceil(widths[k]);
}
}
return strWidth;
}
/**
* 获取字符串高度
*/
private int getStringHeight(Paint paint) {
FontMetrics fm = paint.getFontMetrics();
return (int) (Math.ceil(fm.descent - fm.top) / 1.5);
}
/**
* 将dip转化为pixel
*/
private static int dip2px(Context context, float dipValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dipValue * scale + 0.5f);
}
}