26

I've written a custom View. Now I want to do a little custom animation when the user touches it.

When I say custom, I mean I basically want to render each frame myself, and not use a "predefined" animation like described here.

What is the proper way of implementing this?

aioobe
  • 413,195
  • 112
  • 811
  • 826
  • @AjitSingh, that article describes the standard animations (rotation, translation, etc). What I'm asking about here is custom animations. – aioobe Apr 16 '16 at 15:00

6 Answers6

23

Most flexible (and pretty easy) way to create custom animation is to extend Animation class.

In general:

  1. Set duration of your animation using setDuration() method.
  2. Optionally set the interpolator for your animation using setInterpolator() (for exapmle you can use LinearInterpolator or AccelerateInterpolator etc.)
  3. Override applyTransformation method. Here we interested in interpolatedTime variable which changes between 0.0 and 1.0 and represent the your animation progress.

Here is an example (I'm using this class to change ofsset of my Bitmap. Bitmap itself is drawn in draw method):

public class SlideAnimation extends Animation {

    private static final float SPEED = 0.5f;

    private float mStart;
    private float mEnd;

    public SlideAnimation(float fromX, float toX) {
        mStart = fromX;
        mEnd = toX;

        setInterpolator(new LinearInterpolator());

        float duration = Math.abs(mEnd - mStart) / SPEED;
        setDuration((long) duration);
    }

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        super.applyTransformation(interpolatedTime, t);

        float offset = (mEnd - mStart) * interpolatedTime + mStart;
        mOffset = (int) offset;
        postInvalidate();
    }

}

Also you can modify View by using Transformation#getMatrix().

UPDATE

In case if you're using Android Animator framework (or compatibility implementation - NineOldAndroids) you can just declare setter and getter for your custom View property and animate it directly. Here is an another example:

public class MyView extends View {

    private int propertyName = 50;

    /* your code */

    public int getPropertyName() {
        return propertyName;
    }

    public void setPropertyName(int propertyName) {
        this.propertyName = propertyName;
    }

    /*
    There is no need to declare method for your animation, you 
    can, of course, freely do it outside of this class. I'm including code
    here just for simplicity of answer.
    */
    public void animateProperty() {
        ObjectAnimator.ofInt(this, "propertyName", 123).start();
    }

}
Dmitry Zaytsev
  • 23,650
  • 14
  • 92
  • 146
3
Animation animation = new AnimationDrawable();
animation.addFrame(getResources().getDrawable(R.drawable.exp1), 50);
animation.addFrame(getResources().getDrawable(R.drawable.exp2), 50);
animation.addFrame(getResources().getDrawable(R.drawable.exp3), 50);
animation.addFrame(getResources().getDrawable(R.drawable.exp4), 50);
animation.addFrame(getResources().getDrawable(R.drawable.exp5), 50);
animation.addFrame(getResources().getDrawable(R.drawable.exp6), 50);

This is the code that I use to produce a custom, frame-by-frame animation in my onCreate().

After that I need to start the animation, but must do so inside the UI thread. Therefore I make use of Runnable.

class Starter implements Runnable {
    public void run() {
        animation.stop();
        animation.start();
    }
}

I start that Runnable from an onClick() using the .post() method of ImageView:

((ImageView) findViewById(R.id.ImageToAnimateOnClicking)).post(new Starter());
Cory Trese
  • 1,148
  • 10
  • 23
  • Looks nice. Is it feasible to render those drawables programatically? (The animation depends on where the user clicks...) – aioobe Nov 29 '10 at 07:00
  • The 'AnimationDrawable' 'animation' can be setas the View background via setBackgroundResource. You can also find easy ways to position it absolutely with overlays. probably depends on where the user clicks! (on a button? a surfaceview? an image? a listview?) – Cory Trese Dec 04 '10 at 22:02
1

I assume you create each frame as a bitmap, and then pass it to the Animation directly, instead of getting the Drawable from resource.

Bitmap bm = Bitmap.createBitmap(width,height,Bitmap.Config.ARGB_888);
Canvas c = new Canvas(bm);
.... Draw to bitmap
animation.addFrame(bm,50)
.... repeat for all frames you wish to add.
HaMMeReD
  • 2,440
  • 22
  • 29
  • It's a shame though that I can't tell in advance the number of FPS the device can handle. If it can only handle like 5 FPS, then I shouldn't spend so much resources on rendering a 20 FPS animation... If there is a nice way of "repeatedly" schedule a repaint, and render the frame on demand, I wouldn't have this problem. – aioobe Dec 01 '10 at 13:05
  • 1
    Well, if you used Opengl they should all be able to handle 30fps no problem. And you should be if you are doing anything graphically challenging. There is a HUGE performance difference between Canvas and GL. – HaMMeReD Dec 01 '10 at 20:03
1

My custom animation when replacing Fragment with another Fragment:

getSupportFragmentManager().beginTransaction()
                    .setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left)
                    .replace(currentFragment.getId(), newFragment).commit();
            currentFragment = newFragment;

XML slide_in_right:

<translate android:fromXDelta="100%p" android:toXDelta="0"
    android:duration="1000"/>

XML slide_out_left:

<translate android:fromXDelta="0" android:toXDelta="-100%p"
    android:duration="1000"/>
0

There are four types of animation that you can add to your custom view.

  1. alpha - animate transparency of element
  2. translate - animate position of element
  3. scale - animate size of element
  4. rotate - animate rotation of element

Here is a blog post which explains each one of them in detail.

Once you are done with creating an animation, just use the below code to add that custom animation to the view.

findById(R.id.element).startAnimation(AnimationUtils.loadAnimation(this, R.anim.custom_animation));
Ajit Singh
  • 2,436
  • 23
  • 27
-1

In addition to defining tweened animations in XML you can also define frame-by-frame animations (stored in res/drawable).

<animation-list
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:oneshot="true"
>
    <item android:drawable="@drawable/frame1" android:duration="300" />
    <item android:drawable="@drawable/frame2" android:duration="300" />
    <item android:drawable="@drawable/frame3" android:duration="300" />
</animation-list>

Set the animation as the View background via setBackgroundResource.

If you're looking to do something more complicated, take a look at the Canvas class. See the brief intro on how to draw with Canvas.

Ian G. Clifton
  • 9,349
  • 2
  • 33
  • 34