/**
*/
public class NumberScrollerView extends View {
private String TAG = NumberScrollerView.class.getSimpleName();
public NumberScrollerView(Context context) {
super(context);
init(null);
}
public NumberScrollerView(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs);
}
public NumberScrollerView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(attrs);
}
@SuppressLint("NewApi")
public NumberScrollerView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(attrs);
}
protected int DURATION;
protected float charsPadding;
private DecimalFormat format;
private char[] oldTxt = "¥100,000,000.01".toCharArray();
private char[] newTxt;
private float percent;
private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
private final float[] charPosition = new float[oldTxt.length];
private float $w;
private float num;
private float comma;
private float dot;
private ValueAnimator anim;
// private final String[] numStr = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"};
private final String[] numStr = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"};
private void init(AttributeSet attrs) {
format = new DecimalFormat();
format.applyPattern("'¥'000,000,000.00");
if (attrs != null) {
TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.NumberScrollerView);
int color = a.getColor(R.styleable.NumberScrollerView_txtColor, 0xff000000);
paint.setColor(color);
float textSize = a.getDimension(R.styleable.NumberScrollerView_txtSize, sp2px(13));
paint.setTextSize(textSize);
DURATION = a.getInt(R.styleable.NumberScrollerView_duration, 1500);
charsPadding = a.getDimension(R.styleable.NumberScrollerView_charsPadding, 0);
boolean isbold = a.getBoolean(R.styleable.NumberScrollerView_bold, false);
if (isbold) {
paint.setFakeBoldText(true);
}
a.recycle();
} else {
paint.setColor(0xff000000);
paint.setTextSize(sp2px(30));
DURATION = 1500;
charsPadding = 0;
}
// setData(100000000.00);
if (NumberScrollerView.sCurMoney >= 0 && NumberScrollerView.sCurMoney <= 100000000) {
newTxt = oldTxt = format.format(NumberScrollerView.sCurMoney).toCharArray();
invalidate();
}
}
private void setData(double moneny) {
if (moneny < 0 || moneny > 100000000) {
return;
}
if (anim != null && anim.isRunning()) {
anim.end();
}
newTxt = format.format(moneny).toCharArray();
// Log.d(TAG, "setData: " + new String(newTxt));
if (isEquals(oldTxt, newTxt)) {
return;
}
anim = ValueAnimator.ofFloat(0, 1);
anim.setDuration(DURATION);
anim.setInterpolator(new AccelerateDecelerateInterpolator());
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
percent = (float) animation.getAnimatedValue();
invalidate();
}
});
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationCancel(Animator animation) {
oldTxt = newTxt;
}
@Override
public void onAnimationEnd(Animator animation) {
oldTxt = newTxt;
}
});
anim.start();
}
public void setTextColor(int color) {
paint.setColor(color);
}
public void setTextSize(float sp) {
paint.setTextSize(sp2px(sp));
requestLayout();
}
public void setDuration(int ms) {
DURATION = ms;
}
public void setCharsPadding(int px) {
charsPadding = px;
requestLayout();
}
@Override
protected void onDraw(Canvas canvas) {
Paint.FontMetricsInt fontMetrics = paint.getFontMetricsInt();
int baseline = (getHeight() + 0 - fontMetrics.bottom - fontMetrics.top) / 2;
if (newTxt == null || oldTxt == null || newTxt.length != oldTxt.length) {
return;
}
int height = getHeight();
int width = getWidth();
canvas.clipRect(0, 0, width, height);
//统一往上滚
int firstDifferentPosition = getFirstDifferentPosition(oldTxt, newTxt);
for (int i = 0; i < firstDifferentPosition; i++) {
canvas.drawText(oldTxt, i, 1, charPosition[i], baseline, paint);
}
for (int i = firstDifferentPosition; i < oldTxt.length; i++) {
if (newTxt[i] < '0' || newTxt[i] > '9') {
canvas.drawText(newTxt, i, 1, charPosition[i], baseline, paint);
continue;
}
int space = (newTxt[i] - oldTxt[i] + 10) % 10;
if (space == 0) {//滚动一圈回到自己
space = 10;
}
int distance = space * height;
float dy = percent * distance;
for (int j = 0; j <= space; j++) {
int p = oldTxt[i] + j - '0';
if (p >= 0 && p < numStr.length) {//一般不会越界,除非数字格式化时有问题
canvas.drawText(numStr[p], charPosition[i], baseline - dy + j * height, paint);
}
}
}
}
private int getFirstDifferentPosition(char[] oldTxt, char[] newTxt) {
for (int i = 0; i < oldTxt.length; i++) {
if (oldTxt[i] != newTxt[i]) {
return i;
}
}
return oldTxt.length;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Paint.FontMetricsInt fontMetrics = paint.getFontMetricsInt();
int height = fontMetrics.bottom - fontMetrics.top;
$w = paint.measureText("¥");
num = paint.measureText("0");
comma = paint.measureText(",");
dot = paint.measureText(".");
int width = (int) ($w + 11 * num + comma * 2 + dot + 14 * charsPadding);
setMeasuredDimension(width, height);
// ¥ 1 0 0 , 0 0 0 , 0 0 0 . 0 0
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
charPosition[0] = 0;
charPosition[1] = charPosition[0] + $w + charsPadding;
charPosition[2] = charPosition[1] + num + charsPadding;
charPosition[3] = charPosition[2] + num + charsPadding;
charPosition[4] = charPosition[3] + num + charsPadding;
charPosition[5] = charPosition[4] + comma + charsPadding;
charPosition[6] = charPosition[5] + num + charsPadding;
charPosition[7] = charPosition[6] + num + charsPadding;
charPosition[8] = charPosition[7] + num + charsPadding;
charPosition[9] = charPosition[8] + comma + charsPadding;
charPosition[10] = charPosition[9] + num + charsPadding;
charPosition[11] = charPosition[10] + num + charsPadding;
charPosition[12] = charPosition[11] + num + charsPadding;
charPosition[13] = charPosition[12] + dot + charsPadding;
charPosition[14] = charPosition[13] + num + charsPadding;
}
private boolean isEquals(char[] c1, char[] c2) {
if (c1 == null && c2 == null) {
return true;
}
if (c1 == null || c2 == null) {
return false;
}
if (c1.length != c2.length) {
return false;
}
for (int i = 0; i < c1.length; i++) {
if (c1[i] != c2[i]) {
return false;
}
}
return true;
}
private int sp2px(float spValue) {
final float fontScale = getContext().getResources().getDisplayMetrics().scaledDensity;
return (int) (spValue * fontScale + 0.5f);
}
private long lastUpdateTime;
private int timeInterval = 5 * 1000;//每隔5秒请求一次
private static final int MSG = 1;
private static double sCurMoney = 100000000;// 改成静态,防止首页下拉刷新后先变成100000000再变成最新的余额
private boolean isDetachedFromWindow = true;
private static class InnerHandler extends Handler {
private WeakReference<NumberScrollerView> ref;
public InnerHandler(NumberScrollerView countView) {
ref = new WeakReference<>(countView);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.d("NumberScrollerView", "handleMessage: update money ");
removeMessages(MSG);
NumberScrollerView scrollerView = ref.get();
if (scrollerView == null) {
return;
}
if (scrollerView.sCurMoney <= 0) {
return;
}
if (scrollerView.isDetachedFromWindow) {
return;
}
scrollerView.update();
scrollerView.lastUpdateTime = SystemClock.elapsedRealtime();
sendEmptyMessageDelayed(MSG, scrollerView.timeInterval);
}
}
private Handler mHandler = new InnerHandler(this);
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if (isInEditMode()) {
return;
}
isDetachedFromWindow = false;
handlerIfNeeded(true);
// lastUpdateTime = SystemClock.elapsedRealtime();
// update();
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
isDetachedFromWindow = true;
mHandler.removeMessages(MSG);//移除控件时 移除所有消息
}
@Override
protected void onWindowVisibilityChanged(int visibility) {
super.onWindowVisibilityChanged(visibility);
handlerIfNeeded(visibility == VISIBLE);
}
@Override
public void onWindowFocusChanged(boolean hasWindowFocus) {
super.onWindowFocusChanged(hasWindowFocus);
handlerIfNeeded(hasWindowFocus);
}
@Override
public void setVisibility(int visibility) {
super.setVisibility(visibility);
handlerIfNeeded(visibility == VISIBLE);
}
private void handlerIfNeeded(boolean isneed) {
//可见状态改变时先移除所有消息
mHandler.removeMessages(MSG);
if (isneed && sCurMoney > 0) {//变为可见时
long t = SystemClock.elapsedRealtime() - lastUpdateTime;
if (t > timeInterval) {//若 距离上次更新时间大于 timeInterval 则立即更新。延时一会,避免刚切到该页面时重复多次请求
mHandler.sendEmptyMessageDelayed(MSG, 1000);
} else {//否则延时 SystemClock.elapsedRealtime() - lastUpdateTime 毫秒 后更新。延时一会,避免刚切到该页面时重复多次请求
mHandler.sendEmptyMessageDelayed(MSG, t + 1000);
}
}
}
private void update() {
HttpApi.getRemainAmount(new HttpUtils.HttpCallback<Double>() {
@Override
public void onSuccess(IRemoteResponse<Double> var1) {
sCurMoney = var1.getData();
setData(sCurMoney);
}
@Override
public void onFailed(IRemoteResponse<Double> var1) {
}
});
}
}
数字滚动
最新推荐文章于 2024-02-23 21:02:32 发布