针对ValueAnimator在部分设备上执行无效的替代方法

2019-08-24  本文已影响0人  DON_1007

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一样的效果

circle.gif

完整代码如下:

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;
    }
}
上一篇下一篇

猜你喜欢

热点阅读