数字滚动



/**
 
 */

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) {
            }
        });
    }
}



 

                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值