从textview平滑进度条

时间:2014-03-21 06:48:11

标签: android textview progress-bar

我有一个课程进度条。根据设置值,使用不同的颜色部分填充文本。我希望当我改变当前值时,进度填充在一段时间内从一个值平滑地进行到另一个值,而不是像现在那样通过跳跃。我怎样才能做到这一点? 我的TextProgressBar代码如下:

package com.example.app.customviews;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Shader;
import android.graphics.Shader.TileMode;
import android.util.AttributeSet;
import android.widget.TextView;

import com.example.app.R;

public class TextProgressBar extends TextView {

private final int minValue = 0;
private int maxValue = 100;
private int currentValue = 0;
private float onePercentLenght = 1;

private int[] colors = {Color.WHITE, Color.BLACK};
private float[] pos = {0,1};

public TextProgressBar(Context context, AttributeSet attrs) {
    super(context, attrs);
    TypedArray a = context.getTheme().obtainStyledAttributes(
            attrs,
            R.styleable.TextProgressBar,
            0, 0);

       try {
           maxValue = a.getInt(R.styleable.TextProgressBar_MaxProgress, 100);
           currentValue = a.getInteger(R.styleable.TextProgressBar_CurrentProgress, 0);
           colors[0] = a.getColor(R.styleable.TextProgressBar_ProgressColor, Color.WHITE);
           colors[1] = a.getColor(R.styleable.TextProgressBar_MainColor, Color.BLACK);
       } finally {
           a.recycle();
       }
       initShader();
}

public TextProgressBar(Context context) {
    super(context);
    initShader();
}

@Override
protected void onDraw(Canvas canvas) {
    onePercentLenght = getWidth() / maxValue;
    super.onDraw(canvas);
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}

@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
    super.onLayout(changed, left, top, right, bottom);
    initShader();
}

public void setProgress(int progress) {
    if(progress < minValue) {
        currentValue = minValue;
    }
    else if( progress > maxValue) {
        currentValue = maxValue;
    }
    else {
        currentValue = progress;
    }
    initShader();
    invalidate();
}

public void setMaxProgress(int progress) {
    if(progress>minValue) {
        maxValue = progress;
    }
    else {
        maxValue = minValue;
    }
    invalidate();
}

public int getMaxProgress() {
    return maxValue; 
}

public int getProgress() {
    return currentValue;
}

private void initShader() {
    float x = 0, dx =  (currentValue+1) * onePercentLenght;
    if(dx < 0) {
        dx = 0;
    }
    if(dx - 1 < 0) {
        x = 0;
    }
    else {
        x = dx - 1;
    }
    Shader textShader = new LinearGradient(x, 0, dx, 0, colors, pos, TileMode.CLAMP);
    getPaint().setShader(textShader);
}

}

1 个答案:

答案 0 :(得分:0)

我按照以下方式测试了以下方法:

10,30,延迟150ms,40延迟250ms,80延迟50ms,100延迟450ms。一个奇怪的事情是,虽然日志打印是准时的,但看起来绘图有点延迟,不确定这是否与我的设备有关。但这可以给你一些开始。根据您设置进度的频率,调整MAX_INTERVAL_TIME可以使其更顺畅。如果回调是你从网络获得的东西,那么几乎可以让它完全顺利,因为你无法预测进展。

private static final int MAX_INTERVAL_TIME = 500;
private CountDownTimer mCountDownTimer;

public void setProgress(final int progress) {
    final int startWidth = currentValue == maxValue ? 0 : currentValue;
    final int endWidth = (int) (maxValue * ((float) progress / maxValue));

    if (progress < minValue) {
        currentValue = minValue;
    } else if (progress > maxValue) {
        currentValue = maxValue;
    } else {
        currentValue = progress;
    }

    if (mCountDownTimer != null) {
        mCountDownTimer.cancel();
    }

    mCountDownTimer = new CountDownTimer(MAX_INTERVAL_TIME, 10) {

        @Override
        public void onTick(long millisUntilFinished) {
            float interpolatedTime = 1 - ((float) millisUntilFinished / MAX_INTERVAL_TIME);
            currentValue = startWidth
                    + ((int) ((endWidth - startWidth) * interpolatedTime));

            initShader();
            invalidate();
        }

        @Override
        public void onFinish() {
            if (progress == maxValue) {
                currentValue = maxValue;

                initShader();
                invalidate();
            }
        }
    }.start();
}

如果您知道自己想要为进度设置动画的时间,可以尝试使用现有代码:

final TextProgressBar text = (TextProgressBar) getView().findViewById(
        R.id.test);
final int animTime = 1000;

new CountDownTimer(animTime, 200) {

    @Override
    public void onTick(long millisUntilFinished) {
        float progress = (1 - ((float) millisUntilFinished / (float) animTime))
                * text.getMaxProgress();
        text.setProgress((int) progress);
    }

    @Override
    public void onFinish() {
        text.setProgress(text.getMaxProgress());
    }
}.start();