davnig
davnig

Reputation: 342

How to animate a Drawable in a custom view?

I currently have a custom view with a Drawable resource that I want to animate moving it from one position to another. I know there are two ways to implement PropertyAnimation, you can do it by using ValueAnimation or ObjectAnimation. But with both I didn't find any information on Google docs about how to use them with a Drawable instead of a View. This is the only example I found that is similar to my problem, and so I've tryed to implement it in my code:

MainActivity

public class MainActivity extends AppCompatActivity {

    private Button animate;
    private CustomView mView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mView = new CustomView(MainActivity.this);

        animate = (Button) findViewById(R.id.animate);
        animate.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mView.startAnimation();
            }
        });

    }
}

CustomView

public class CustomView extends View {

    private Drawable drawable;
    private Rect drawableRect;
    private int newPos;

    public CustomView(Context context) {
        super(context);

        drawable = ContextCompat.getDrawable(context, R.drawable.my_drawable);
        drawableRect= new Rect();
        newPos = 0;
    }

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

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        drawableRect.left = 0;
        drawableRect.top = newPos;
        drawableRect.right = drawable.getIntrinsicWidth();
        drawableRect.bottom = newPos + drawable.getIntrinsicHeight();

        drawable.setBounds(drawableRect);
        drawable.draw(canvas);

    }

    public void startAnimation() {

        ValueAnimator animator = ValueAnimator.ofFloat(0, 200);
        animator.setDuration(1500);

        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                newPos = ((Float) valueAnimator.getAnimatedValue()).intValue();
                CustomView.this.invalidate();
            }
        });

        animator.start();
        invalidate();

    }

}

But with no effect. The value of newPos changes properly (checked with Logs) and the screen gets updated (checked with surface update) but the Drawable does not move. What am I doing wrong? Hoping in any help.

Upvotes: 0

Views: 3039

Answers (3)

xriminact
xriminact

Reputation: 73

The view is not added/updated in the layout yet. An object of CustomView is created but it's not put on the screen.

frameParentLayout = (FrameLayout) findViewById(R.id.parent_view);   

mView = new CustomView(MainActivity.this);     

frameParentLayout.addView(mView);

Upvotes: 0

davnig
davnig

Reputation: 342

周恩旭 eventually took me to the solution. I was doing a stupid error in MainActivity because I was creating a new reference to the CustomView:

mView = new CustomView(MainActivity.this);

and trying to animate using that object reference. Solved this by replacing it with:

mView = (CustomView) findViewById(R.id.custom_view);

Upvotes: 1

周恩旭
周恩旭

Reputation: 121

I try to run your code that the CustomView, it's efficient, it's have animation.

Are you sure you execute the method startAnimation?

I add the startAnimation() to the construction NoteCustomView, I can see the animation when UI finish load.

Code at below, I use the ic_launcher as drawable. And I add the NoteCustomView to activity's layout xml.

public class NoteCustomView extends View {

    private Drawable drawable;
    private Rect drawableRect;
    private int newPos;

    public NoteCustomView(Context context) {
        this(context, null);

    }

    public NoteCustomView(final Context context, @Nullable final AttributeSet attrs) {
        super(context, attrs);
        drawable = ContextCompat.getDrawable(context, R.mipmap.ic_launcher_round);
        drawableRect= new Rect();
        newPos = 0;
        startAnimation();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        drawableRect.left = 0;
        drawableRect.top = newPos;
        drawableRect.right = drawable.getIntrinsicWidth();
        drawableRect.bottom = newPos + drawable.getIntrinsicHeight();

        drawable.setBounds(drawableRect);
        drawable.draw(canvas);

    }

    public void startAnimation() {

        ValueAnimator animator = ValueAnimator.ofFloat(0, 200);
        animator.setDuration(1500);

        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                newPos = ((Float) valueAnimator.getAnimatedValue()).intValue();
                NoteCustomView.this.invalidate();
            }
        });

        animator.start();
        invalidate();

    }

}

Upvotes: 3

Related Questions