Getting ValueAnimator value out to onDraw

I’m confused with instructions in this page this. Working on the below function.

PropertyValuesHolder propertyRadius = PropertyValuesHolder.ofInt(PROPERTY_RADIUS, 0, 150);
PropertyValuesHolder propertyRotate = PropertyValuesHolder.ofInt(PROPERTY_ROTATE, 0, 360);

animator = new ValueAnimator();
animator.setValues(propertyRadius, propertyRotate);
animator.setDuration(2000);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        radius = (int) animation.getAnimatedValue(PROPERTY_RADIUS);
        rotate = (int) animation.getAnimatedValue(PROPERTY_ROTATE);
        invalidate();
    }
});
animator.start();

He stated that calling this method to do the rotation. As I did was declaring “radius” and “rotate” variable in global and put below code to “onDraw” method so invalidate will update Canvas.

canvas.rotate(rotate, viewWidth, viewHeight);

Problem: I can’t seems to get the “radius” or “rotate” variable out of below code. It keeps returning “0” when I inserted a log inside OnDraw to check on “rotate” value. I’m still learning about this canvas thingy.

 public void onAnimationUpdate(ValueAnimator animation) {
        radius = (int) animation.getAnimatedValue(PROPERTY_RADIUS);
        rotate = (int) animation.getAnimatedValue(PROPERTY_ROTATE);
        invalidate();
    }

UPDATE

here is my full code:

public class DrawingShapes extends View {
    private String PROPERTY_ROTATE = "PROPERTY_ROTATE", PROPERTY_RADIUS = "PROPERTY_RADIUS";

    private Context mContext;

    private int radius, rotate;


    public DrawingShapes(Context context) {
        super(context);
    }

    public DrawingShapes(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        mContext = context;
    }


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        drawAnim();
        Log.i("TAG", "checking DrawingShapes rotate = " + rotate);

    }
    

    public static int convertDpToPixel(Context context, int idp) {
        return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, (float) idp, context.getResources().getDisplayMetrics()));
    }

    public void drawAnim() {
        PropertyValuesHolder propertyRadius = PropertyValuesHolder.ofInt(PROPERTY_RADIUS, 0, 150);
        PropertyValuesHolder propertyRotate = PropertyValuesHolder.ofInt(PROPERTY_ROTATE, 0, 360);

        ValueAnimator animator = new ValueAnimator();
        animator.setValues(propertyRadius, propertyRotate);
        animator.setDuration(100);
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                radius = (int) animation.getAnimatedValue(PROPERTY_RADIUS);
                rotate = (int) animation.getAnimatedValue(PROPERTY_ROTATE);
                Log.i("TAG", "checking DrawingShapes rotate = " + rotate);
                invalidate();
            }
        });

        animator.start();
    }
    
}

Answer

You’re starting the animation in onDraw, which doesn’t make any sense. onDraw should only be used for drawing, not anything else.

To highlight why it would be nonsensical, consider what your code is actually doing:

onDraw starts the animation, which repeatedly calls invalidate. This then triggers onDraw to be called again, which then starts another animation, which repeatedly calls invalidate, …., etc.

You should be starting the animation when you want it to start, like when the view is instantiated, or manually if it responds to some sort of trigger. For example:

class DrawingShapes ... {

    private int radius;

    DrawingShapes(...) {

        ...
        startAnimation();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        
        drawCircleWithRadius(radius);
    }

    private void startAnimation() {

        ValueAnimator animator = new ValueAnimator();
        ...
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {

                radius = ...
                invalidate();
            }
        });

        animator.start();
    }
}