Property Animations

Old notes on animations

primary blog


ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);    
anim.setDuration(500);    
anim.start();

anim.addUpdateListener(
    new ValueAnimator.AnimatorUpdateListener() 
    {        
        public void onAnimationUpdate(ValueAnimator animation) 
        {            
            Float value = (Float) animation.getAnimatedValue();            
            // do something with value...        
        }    
    }
);

<animator xmlns:android="http://schemas.android.com/apk/res/android"        
 android:valueFrom="0"        
 android:valueTo="100"        
 android:valueType="intType"/>

The graphics blog


private void animateTextView(TextView tv)
{
    //Fade out if it is visible, making it invisible
    if (tv.getAlpha() != 0)
    {
        ObjectAnimator fadeOut = 
            ObjectAnimator.ofFloat(m_tv, "alpha", 0f);
        fadeOut.start();
    }
    //Fade in if it is invisible, makign it visible
    else
    {
        ObjectAnimator fadeIn = 
            ObjectAnimator.ofFloat(m_tv, "alpha", 1f);
        fadeIn.start();
    }
}

api: ValueAnimator

See this link to see what methods and attributes, callbacks are avialble.

Animation package API

See all the classes in the animation package here

AnimatorSet api

The AnimationSetBuilder api


private void animateTv1(TextView m_tv)
{
    m_tv.setAlpha(1f);
    ObjectAnimator fadeOut = 
        ObjectAnimator.ofFloat(m_tv, "alpha", 0f);
    ObjectAnimator fadeIn = 
        ObjectAnimator.ofFloat(m_tv, "alpha", 1f);
    AnimatorSet as = new AnimatorSet();
    as.playSequentially(fadeOut,fadeIn);
    as.setDuration(2000); //2 secs
    as.start();
}

So chaining is possible

This is purely a utility class that allows you establish reslationship between the individual animations in a set. Whether to run the animations serially, parallely or to run before or to run after etc.

if you can do this relationships with the animator set itself explicitly then you can use it as such.


playTogether(list of animators)
playSequentially(list of animators)

public void testAnimationBuilder(View v)
{
    m_tv.setAlpha(1f);
    ObjectAnimator fadeOut = 
        ObjectAnimator.ofFloat(m_tv, "alpha", 0f);
    ObjectAnimator fadeIn = 
        ObjectAnimator.ofFloat(m_tv, "alpha", 1f);
    AnimatorSet as = new AnimatorSet();
    as.play(fadeOut).before(fadeIn);
    as.setDuration(2000); //2 secs
    as.start();
}

You start with a single animator

you will use "play" against that single animator to start the builder. This first animator becomes the animator of focus. All subsequent animations used by

before
after
with

are in relation to the first animator.

In the end you start the animator set and not the builder. The duration and interpolators etc also apply to the animator set and animators and not to the builder.


valueanimator
objectanimator
animatorset
animatorset.builder
xml animators
view properties to animate

See this link to see fragment animations and some stock animation xml files

see this link as well: sdk property animations

This link has a list of interpolators

Understadn view property animator by reading this blog

Understand layouttransition class

viewpropertyanimator api

Constructs and returns an ObjectAnimator that animates between int values. A single value implies that that value is the one being animated to. Two values imply a starting and ending values. More than two values imply a starting value, values to animate through along the way, and an ending value (these values will be distributed evenly across the duration of the animation).


//Go to 50 on x
PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("x", 50f);

//Go to 100 on y
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("y", 100f);

//Do them both x and y
ObjectAnimator.ofPropertyValuesHolder(myView, pvhX, pvyY).start();

it is instigated by calling "animate()" on any view

The sets on the view property animator are cumulative for this frame: that is a bit similar to OpenGL if I remember right

All the animations are clubbed and played when the UI thread gets around to it on subsequent frame refreshes

In Android how can i set start values for a view property animator?

Search for: In Android how can i set start values for a view property animator?

viewpropertyanimator

Search Google for: viewpropertyanimator

Search Android Developers Group for: viewpropertyanimator

Search Android Beginers Group for: viewpropertyanimator

Search Google Code for: viewpropertyanimator

Search Android Issues Database for: viewpropertyanimator


public void testPropertiesHolder(View m_tv)
{
    m_tv.setAlpha(1f);
    float h = m_tv.getHeight();
    float w = m_tv.getWidth();
    float x = m_tv.getX();
    float y = m_tv.getY();

    //Set the view to the right bottom
    m_tv.setX(w);
    m_tv.setY(h);
    
    //Move the view to the right top
    //set x to original x
    PropertyValuesHolder pvhX = 
        PropertyValuesHolder.ofFloat("x", x);

    //set y to original y
    PropertyValuesHolder pvhY = 
        PropertyValuesHolder.ofFloat("y", y);
    
    ObjectAnimator oa
    = ObjectAnimator.ofPropertyValuesHolder(m_tv, pvhX, pvhY);
    oa.setDuration(5000); //2 secs
    oa.start();
}

android.animation
android.view.animation

android.animation

Key classes

animators
  value
  object
  animatorset
PropertyValuesHolder
TypeEvaluator

android.view.animation

Key classes

interpolators
Older animations
  scale
  translate
  rotate
  transform

ObjectAnimator oa
  = ObjectAnimator.ofPropertyValuesHolder(m_tv, pvhX, pvhY);
oa.setDuration(5000); //5 secs
oa.setInterpolator(
  new  AccelerateDecelerateInterpolator());

x=0 and y=0 referes to the relative top-left corner of the parent view.

By default a layout clips its children

Unless you pay attention and control the height of the linear layout it may take the entire space left in the activity if it is the last one. To control it otherwise use the wrap_content options for height instead of match or fill parent.


public class MyAnimatableView 
{
    PointF curPoint = null;
    View m_v = null;
    public MyAnimatableView(View v)
    {
        curPoint = new PointF(v.getX(),v.getY());
        m_v = v;
    }
    
    public PointF getCurPointF()
    {
        return curPoint;
    }
    public void setPoint(PointF p)
    {
        curPoint = p;
        m_v.setX(p.x);
        m_v.setY(p.y);
    }
}

Keep a local pointer to a view such as a text view. Keep this parent object in your activity as a local variable.

Have a set method on the view that can change what you want to change such as the position of the view.

All you have to do now is to find a mechanism to invoke "setPoint" frequently.

This can be done by an object animator

Pass the object animator this object, and the name of the method and the startign point and the ending point.

This is done through object animators adn type evaluators. Here is the driver code for this first and then I will show you the type evaluator that knows to vary points over time


public void testTypeEvaluator(TextView m_tv, 
                     MyAnimatableView m_atv)
{
    m_tv.setAlpha(1f);
    
    float h = m_tv.getHeight();
    float w = m_tv.getWidth();
    float x = m_tv.getX();
    float y = m_tv.getY();
    
    ObjectAnimator tea = 
        ObjectAnimator.ofObject(m_atv
            ,"point"
            ,new MyPointEvaluator()
            ,new PointF(w,h)
            ,new PointF(x,y));
    tea.setDuration(5000);
    tea.start();
}

public class MyPointEvaluator 
implements TypeEvaluator<PointF> 
{
    public PointF evaluate(float fraction, 
            PointF startValue, 
            PointF endValue) 
    {            
        PointF startPoint = (PointF) startValue;            
        PointF endPoint = (PointF) endValue;            
        return new PointF(
            startPoint.x + fraction * (endPoint.x - startPoint.x),
            startPoint.y + fraction * (endPoint.y - startPoint.y));        
    }
}

The previous animations are now considered legacy!!

New: /res/animator

old: /res/anim


ValueAnimator - <animator>
ObjectAnimator - <objectAnimator>
AnimatorSet - <set>

See this link to see a quick guide to using animations XMLs

Use this link for a reference of each of the xmls


<?xml version="1.0" encoding="utf-8" ?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
    android:interpolator="@android:interpolator/accelerate_cubic"
    android:valueFrom="0"
    android:valueTo="1280"
    android:valueType="floatType"
    android:propertyName="y"
    android:duration="2000" />
<objectAnimator
    android:interpolator="@android:interpolator/accelerate_cubic"
    android:valueFrom="1"
    android:valueTo="0"
    android:valueType="floatType"
    android:propertyName="alpha"
    android:duration="2000" />
</set>

public void sequentialAnimationXML(TextView m_tv)
{
    m_tv.setAlpha(1f);
    AnimatorSet set = (AnimatorSet) 
        AnimatorInflater.loadAnimator(this,    
                R.animator.fadein);
    set.setTarget(m_tv);
    set.start();    
}

public void testKeyFrames(View v)
{
    m_tv.setAlpha(1f);
    
    float h = m_tv.getHeight();
    float w = m_tv.getWidth();
    float x = m_tv.getX();
    float y = m_tv.getY();

    //Start frame : 0.2
    //alpha: 0.8
    Keyframe kf0 = Keyframe.ofFloat(0.2f, 0.8f);
    
    //Middle frame: 0.5
    //alpha: 0.2
    Keyframe kf1 = Keyframe.ofFloat(.5f, 0.2f);
    
    //end frame: 0.8
    //alpha: 0.8
    Keyframe kf2 = Keyframe.ofFloat(0.8f, 0.8f);        
    PropertyValuesHolder pvhAlpha = 
        PropertyValuesHolder.ofKeyframe("alpha", kf0, kf1, kf2);
    
    PropertyValuesHolder pvhX = 
        PropertyValuesHolder.ofFloat("x", w, x);
    
    //end frame
    ObjectAnimator anim = 
        ObjectAnimator.ofPropertyValuesHolder(m_tv, pvhAlpha,pvhX);
    anim.setDuration(5000);
    anim.start();
}

layout transitions are nicely documented here as part of the api

To enable layout transitions on a view group you will do

viewgroup.setLayoutTransition(
  new LayoutTransition()
);

The layout transistion comes with its own set of 4 animators for each of the 4 transitions.


add a view (appearing)
change appearing (rest of the items in layout)

remove a view (disappearing)
change disappearing (rest of the items in layout)

LayoutTransition lt 
= new LayoutTransition();

someLayout.setLayoutTransition(lt);

//obtain a default animator if you 
//need to remember
Animator defaultAppearAnimator 
= lt.getAnimator(APPEARING);

//create a new animator
ObjectAnimator someNewObjectAnimator;

//set it as your custom animator
lt.setAnimator(someNewObjectAnimator);

Because the animator you supply to a layout transition applies to each view, they get internally cloned before being applied to each view.

Key listening interfaces on an animator: Animator.AnimatorListener

onAnimationCancel
  End
  Repeat
  Start

Read the above URL for more details, but if the views are moving in and out the clicks on views may not be predictable when they are in motion.

I wills start with a picture of what I am trying to animate and using what aspects of property animations


An object animator to fade out and fade in individually
An object animator to fade out and fade in sequentially
Use an object animator builder to tie multiple animations together 
  in a relationship.
Use XML to load an animation from a resource file
Use Property Values Holder to animate multiple values
Use view property animator to optimize view animation
Use a type evaluator to move an object in 2 dimensions
Use key frames for checkered progress

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <Button
        android:id="@+id/btn_st_animation"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="toggleAnimation"
        android:text="Fade Out: Animator" />
    
    <Button
        android:id="@+id/btn_st_animation1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="sequentialAnimation"
        android:text="FadeOut/FadeIn: Sequential" />
    
    <Button
        android:id="@+id/btn_st_animation1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="testAnimationBuilder"
        android:text="FadeOut/FadeIn: Builder" />
    
    <Button
        android:id="@+id/btn_st_animation1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="sequentialAnimationXML"
        android:text="FadeOut/FadeIn XML" />
    
    <Button
        android:id="@+id/btn_st_animation1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="testPropertiesHolder"
        android:text="PVHolder" />
    <Button
        android:id="@+id/btn_st_animation1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="testViewAnimator"
        android:text="ViewAnimator" />
    
    <Button
        android:id="@+id/btn_st_animation1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="testTypeEvaluator"
        android:text="Type Evaluator" />
    
    <Button
        android:id="@+id/btn_st_animation1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="testKeyFrames"
        android:text="Key Frames" />
    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        >
        <TextView
            android:id="@+id/tv_id"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:background="@color/blue"
            android:textColor="@color/white"
            android:text="@string/hello" />
    </LinearLayout>
</LinearLayout>

There are just a series of buttons that are tied to functions.

The text view is ensconced in a second linear layout because this will allow me to set the "x" and "y" values with respect to this layouts position that excludes the buttons. Otherwise the "x" and "y" values will be that of the bigger parent.


public class TestPropertyAnimationActivity extends Activity 
{
    private static String tag = "My activity";
    private TextView m_tv = null;
    private MyAnimatableView m_atv = null;
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        gatherControls();
    }
    private void gatherControls()
    {
        m_tv = (TextView)this.findViewById(R.id.tv_id);
        m_atv = new MyAnimatableView(m_tv);
    }
    public void toggleAnimation(View btnView)
    {
        Button tButton = (Button)btnView;
        if (m_tv.getAlpha() != 0)
        {
            ObjectAnimator fadeOut = 
                ObjectAnimator.ofFloat(m_tv, "alpha", 0f);
            fadeOut.setDuration(5000);
            fadeOut.start();
            tButton.setText("Fade In");
        }
        else
        {
            ObjectAnimator fadeIn = 
                ObjectAnimator.ofFloat(m_tv, "alpha", 1f);
            fadeIn.setDuration(5000);
            fadeIn.start();
            tButton.setText("Fade out");
        }
    }
    public void sequentialAnimation(View bView)
    {
        m_tv.setAlpha(1f);
        ObjectAnimator fadeOut = 
            ObjectAnimator.ofFloat(m_tv, "alpha", 0f);
        ObjectAnimator fadeIn = 
            ObjectAnimator.ofFloat(m_tv, "alpha", 1f);
        AnimatorSet as = new AnimatorSet();
        as.playSequentially(fadeOut,fadeIn);
        as.setDuration(5000); //5 secs
        as.start();
    }
    public void sequentialAnimationXML(View bView)
    {
        m_tv.setAlpha(1f);
        AnimatorSet set = (AnimatorSet) 
            AnimatorInflater.loadAnimator(this,    
                    R.animator.fadein);
        set.setTarget(m_tv);
        set.start();    
    }
    public void testAnimationBuilder(View v)
    {
        m_tv.setAlpha(1f);
        ObjectAnimator fadeOut = 
            ObjectAnimator.ofFloat(m_tv, "alpha", 0f);
        ObjectAnimator fadeIn = 
            ObjectAnimator.ofFloat(m_tv, "alpha", 1f);
        AnimatorSet as = new AnimatorSet();
        as.play(fadeOut).before(fadeIn);
        as.setDuration(2000); //2 secs
        as.start();
    }
    public void testPropertiesHolder(View v)
    {
        m_tv.setAlpha(1f);
        float h = m_tv.getHeight();
        float w = m_tv.getWidth();
        float x = m_tv.getX();
        float y = m_tv.getY();
    
        m_tv.setX(w);
        m_tv.setY(h);
        //Go to 50 on x
        PropertyValuesHolder pvhX = 
            PropertyValuesHolder.ofFloat("x", x);

        //Go to 100 on y
        PropertyValuesHolder pvhY = 
            PropertyValuesHolder.ofFloat("y", y);
        
        ObjectAnimator oa
        = ObjectAnimator.ofPropertyValuesHolder(m_tv, pvhX, pvhY);
        oa.setDuration(5000); //2 secs
        oa.setInterpolator(
                new  AccelerateDecelerateInterpolator());
        oa.start();
    }
    public void testViewAnimator(View v)
    {
        m_tv.setAlpha(1f);
        float h = m_tv.getHeight();
        float w = m_tv.getWidth();
        float x = m_tv.getX();
        float y = m_tv.getY();
    
        m_tv.setX(w);
        m_tv.setY(h);
        
        ViewGroup layout = (ViewGroup)m_tv.getParent();
        layout.setClipChildren(true);
        
        //Go to 50 on x
        ViewPropertyAnimator vpa = m_tv.animate();
        vpa.x(x);
        vpa.y(y);
        
        vpa.setDuration(5000); //2 secs
        vpa.setInterpolator(
                new  AccelerateDecelerateInterpolator());
        //vpa.start();
    }
    public void testTypeEvaluator(View v)
    {
        m_tv.setAlpha(1f);
        
        float h = m_tv.getHeight();
        float w = m_tv.getWidth();
        float x = m_tv.getX();
        float y = m_tv.getY();
        
        ObjectAnimator tea = 
            ObjectAnimator.ofObject(m_atv
                ,"point"
                ,new MyPointEvaluator()
                ,new PointF(w,h)
                ,new PointF(x,y));
        tea.setDuration(5000);
        tea.start();
        
    }
    public void testKeyFrames(View v)
    {
        m_tv.setAlpha(1f);
        
        float h = m_tv.getHeight();
        float w = m_tv.getWidth();
        float x = m_tv.getX();
        float y = m_tv.getY();

        //Start frame : 0.2
        //alpha: 0.8
        Keyframe kf0 = Keyframe.ofFloat(0.2f, 0.8f);
        
        //Middle frame: 0.5
        //alpha: 0.2
        Keyframe kf1 = Keyframe.ofFloat(.5f, 0.2f);
        
        //end frame: 0.8
        //alpha: 0.8
        Keyframe kf2 = Keyframe.ofFloat(0.8f, 0.8f);        
        PropertyValuesHolder pvhAlpha = 
            PropertyValuesHolder.ofKeyframe("alpha", kf0, kf1, kf2);
        
        PropertyValuesHolder pvhX = 
            PropertyValuesHolder.ofFloat("x", w, x);
        
        //end frame
        ObjectAnimator anim = 
            ObjectAnimator.ofPropertyValuesHolder(m_tv, pvhAlpha,pvhX);
        anim.setDuration(5000);
        anim.start();
    }
}

For the type evaluator animation you will need two other files


public class MyPointEvaluator 
implements TypeEvaluator<PointF> 
{
    public PointF evaluate(float fraction, 
            PointF startValue, 
            PointF endValue) 
    {            
        PointF startPoint = (PointF) startValue;            
        PointF endPoint = (PointF) endValue;
        return new PointF(
            startPoint.x + fraction * (endPoint.x - startPoint.x),
            startPoint.y + fraction * (endPoint.y - startPoint.y));        
    }
}

public class MyAnimatableView 
{
    PointF curPoint = null;
    View m_v = null;
    public MyAnimatableView(View v)
    {
        curPoint = new PointF(v.getX(),v.getY());
        m_v = v;
    }
    
    public PointF getCurPointF()
    {
        return curPoint;
    }
    public void setPoint(PointF p)
    {
        curPoint = p;
        m_v.setX(p.x);
        m_v.setY(p.y);
    }
}

<?xml version="1.0" encoding="utf-8" ?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:ordering="sequentially">
<objectAnimator
    android:interpolator="@android:interpolator/accelerate_cubic"
    android:valueFrom="1"
    android:valueTo="0"
    android:valueType="floatType"
    android:propertyName="alpha"
    android:duration="2000" />
<objectAnimator
    android:interpolator="@android:interpolator/accelerate_cubic"
    android:valueFrom="0"
    android:valueTo="1"
    android:valueType="floatType"
    android:propertyName="alpha"
    android:duration="2000" />
</set>

Although I called it fadein.xml, it actually does fade out first followed by fadein.

default value for ValueAnimator setFrameDelay

Search for: default value for ValueAnimator setFrameDelay

It states here that it is 10 ms, from the guide

lifetime of valueanimator object in android

Search for: lifetime of valueanimator object in android

when is a valueanimator garbage collected?

Search for: when is a valueanimator garbage collected?