美文网首页
针对ValueAnimator在部分设备上执行无效的替代方法

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

作者: DON_1007 | 来源:发表于2019-08-24 17:43 被阅读0次

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

    相关文章

      网友评论

          本文标题:针对ValueAnimator在部分设备上执行无效的替代方法

          本文链接:https://www.haomeiwen.com/subject/dscqectx.html