ValueAnimator
在部分设备上不能很好的执行,通过onAnimationUpdate
得到的值总是0
ValueAnimator.AnimatorUpdateListener animatorUpdateListener = new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int value = (int) animation.getAnimatedValue();
mDegress = value;
invalidate();
}
};
ValueAnimator valueAnimator = ValueAnimator.ofInt(0, 360);
valueAnimator.addUpdateListener(animatorUpdateListener);
valueAnimator.setDuration(1600);
valueAnimator.setInterpolator(new DecelerateInterpolator(0.6f));
valueAnimator.setRepeatCount(-1);
valueAnimator.start();
原因是 动画时长缩放程序 这个选项被关闭了,点击查看详情
解决方式有两种:
1、就像上面的文章中提到的,通过反射修改 动画时长缩放程序 的值
2、从动画插值器中得到 getInterpolation(float input)
方法,根据动画执行时长和动画执行总时长计算出当前的值
以 Android UI 自定义渐进圆形进度条为例,部分设备上无法根据onAnimationUpdate
更新进度,在onDraw
方法中,我们根据动画执行时长和动画执行总时长调用DecelerateInterpolator
中的getInterpolation
方法得到当前的进度
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
...
if (mStartTime == 0) {
mStartTime = System.currentTimeMillis();
}
mDegrees = (int) (getInterpolation((System.currentTimeMillis() - mStartTime) / (float) DEFAULT_DURATION) * 360);
canvas.drawArc(mCircleRecF, mDegrees, 360 - mDegrees < MAXDEGREES ?
360 - mDegrees : Math.min(mDegrees, MAXDEGREES), false, mPaint);
if ((System.currentTimeMillis() - mStartTime) > DEFAULT_DURATION) {
mStartTime = 0;
}
invalidate();
}
// 从DecelerateInterpolator拷贝
public float getInterpolation(float input) {
float result;
float factor = 0.5f;
if (factor == 1.0f) {
result = (float) (1.0f - (1.0f - input) * (1.0f - input));
} else {
result = (float) (1.0f - Math.pow((1.0f - input), 2 * factor));
}
return result;
}
最终可以达到和Android UI 自定义渐进圆形进度条中使用ValueAnimator
一样的效果
完整代码如下:
public class CircleProgress extends View {
private final String TAG = "CircleProgress";
private final int COLOR_CIRCLE_BG = Color.parseColor("#4affffff");
private final long DEFAULT_DURATION = 1200;
private Context mContext;
private int mDegrees = 360;
private final int MAXDEGREES = 120;
private int SCREEN_WIDTH = 0;
private int circleWidth = 0;
private int circleColor = Color.WHITE;
private int mWidth, mHeight, mSize, mLeft, mTop;
private RectF mCircleRecF = null;
private Paint mPaint = new Paint();
private long mStartTime = 0;
public CircleProgress(Context context) {
this(context, null, 0);
}
public CircleProgress(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CircleProgress(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
mContext = getContext();
SCREEN_WIDTH = getScreenWidth(mContext);
circleWidth = getRelativeWidth(8);
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setStrokeWidth(circleWidth);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeCap(Paint.Cap.ROUND);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (mCircleRecF == null) {
if (getWidth() <= 0 || getHeight() <= 0) {
return;
}
mWidth = getWidth();
mHeight = getHeight();
mSize = Math.min(mWidth, mHeight) - circleWidth - 4;
mLeft = (mWidth - mSize) / 2 + 1;
mTop = (mHeight - mSize) / 2 + 1;
mCircleRecF = new RectF(mLeft, mTop, mLeft + mSize, mTop + mSize);
}
mPaint.setColor(COLOR_CIRCLE_BG);
canvas.drawCircle(mLeft + mSize / 2, mTop + mSize / 2, mSize / 2, mPaint);
mPaint.setColor(circleColor);
if (mStartTime == 0) {
mStartTime = System.currentTimeMillis();
}
mDegrees = (int) (getInterpolation((System.currentTimeMillis() - mStartTime) / (float) DEFAULT_DURATION) * 360);
canvas.drawArc(mCircleRecF, mDegrees, 360 - mDegrees < MAXDEGREES ?
360 - mDegrees : Math.min(mDegrees, MAXDEGREES), false, mPaint);
if ((System.currentTimeMillis() - mStartTime) > DEFAULT_DURATION) {
mStartTime = 0;
}
invalidate();
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
Log.i(TAG, "onAttachedToWindow");
mStartTime = 0;
}
public float getInterpolation(float input) {
float result;
float factor = 0.5f;
if (factor == 1.0f) {
result = (float) (1.0f - (1.0f - input) * (1.0f - input));
} else {
result = (float) (1.0f - Math.pow((1.0f - input), 2 * factor));
}
return result;
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
Log.i(TAG, "onDetachedFromWindow");
}
public int getRelativeWidth(int pxValue) {
if (SCREEN_WIDTH <= 0) {
return pxValue;
}
return (int) (pxValue * SCREEN_WIDTH / 1920.f);
}
public int getScreenWidth(Context context) {
DisplayMetrics displayMetrics = new DisplayMetrics();
WindowManager windowManager = (WindowManager) context
.getSystemService(Context.WINDOW_SERVICE);
windowManager.getDefaultDisplay().getMetrics(displayMetrics);
return displayMetrics.widthPixels;
}
public int getCircleWidth() {
return circleWidth;
}
public void setCircleWidth(int circleWidth) {
this.circleWidth = circleWidth;
mPaint.setStrokeWidth(circleWidth);
}
public int getCircleColor() {
return circleColor;
}
public void setCircleColor(int circleColor) {
this.circleColor = circleColor;
}
}
网友评论