Tuesday, October 19, 2010

Frame animation - circular spinner implementation

With respect to earlier post of how to implement progress bar using level-list drawable, today i will take you in steps of achieving a similar kinda of animation using Frame animation.

Level-list & animation-list both are used for changing the images.

<Level-list> has some meaning like based on some conditions, or level u can pick the up the image. Where as resource just shows the frame one by one with a duration applied to each frame.

1 - Take the images and keep in drawable directory. And write the animation xml file and place it in anim folder. (/res/anim )



<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android" id="selected" android:oneshot="false">
<item android:drawable="@drawable/circular1" android:duration="500" />
<item android:drawable="@drawable/circular2" android:duration="500" />
<item android:drawable="@drawable/circular3" android:duration="500" />
<item android:drawable="@drawable/circular4" android:duration="500" />
<item android:drawable="@drawable/circular5" android:duration="500" />
<item android:drawable="@drawable/circular7" android:duration="500" />
<item android:drawable="@drawable/circular8" android:duration="500" />
<item android:drawable="@drawable/circular9" android:duration="500" />
<item android:drawable="@drawable/circular10" android:duration="500" />
<item android:drawable="@drawable/circular11" android:duration="500" />
<item android:drawable="@drawable/circular1" android:duration="500" />
</animation-list>



I have kept the circular spinner images in drawable directory.

android:duration - Tells in milliseconds a frame would be shown.
android:oneshot - If true, keep showing frames in a loop from starting to ending and then again starting. If false, when animation started, shows the frames only once from starting to ending.

2 - This animation can be applied to all widgets (to a linear layout, Imageview, Button etc. )

There are two approaches you can do this.

1 - Create the animation-list drawable and set it in the layout's background property / or set it in the code. ( 2 ways )



<LinearLayout android:id="@+id/urlBar"
android:layout_width="fill_parent"
android:layout_height="50px"
android:background="@anim/layoutanimation"
android:orientation="horizontal">

or

ViewGroup lyout = (ViewGroup)findViewById(R.id.urlBar);
layout.setBackgroundResource(R.anim.layoutanimation);




Next step is common for noth of the above cases to get the AnimationDrawable object.



AnimationDrawable animation;
animation = (AnimationDrawable) l.getBackground();
animtion.start();



2 - Another way is create a AnimationDrawable object and add frames to it. Then set the drawable object as backgroundDrawable to the widget.



AnimationDrawable animation;
animation.addFrame(getResources().getDrawable(R.drawable.circular1), 500);
animation.addFrame(getResources().getDrawable(R.drawable.circular2), 500);
animation.addFrame(getResources().getDrawable(R.drawable.circular3), 500);
animation.addFrame(getResources().getDrawable(R.drawable.circular4), 500);
animation.setOneShot(false);

ViewGroup layout = (ViewGroup)findViewById(R.id.urlBar);
layout.setBackgroundDrawable(animation);

animation.start();



One catch here, which every one must know is, if you expect your animation to start in the onCreate() of activity, then sorry, it will not start.

http://developer.android.com/guide/topics/graphics/2d-graphics.html

Please read at the end of the page. It says why it will not work. :)

Now lets look at full example.
1 - Apply frame animation to Linear Layout. [a set of gradient images will be applied]
2 - Apply frame animation to a Image View. [ circular spinner holder ]




layoutanimation.xml



<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android" id="selected" android:oneshot="false">
<item android:drawable="@drawable/gradient_25" android:duration="500" />
<item android:drawable="@drawable/gradient_50" android:duration="500" />
<item android:drawable="@drawable/gradient_75" android:duration="500" />
<item android:drawable="@drawable/gradient_100" android:duration="500" />

</animation-list>



imageanimation.xml


<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android" id="selected" android:oneshot="false">
<item android:drawable="@drawable/circular1" android:duration="500" />
<item android:drawable="@drawable/circular2" android:duration="500" />
<item android:drawable="@drawable/circular3" android:duration="500" />
<item android:drawable="@drawable/circular4" android:duration="500" />
<item android:drawable="@drawable/circular5" android:duration="500" />
<item android:drawable="@drawable/circular7" android:duration="500" />
<item android:drawable="@drawable/circular8" android:duration="500" />
<item android:drawable="@drawable/circular9" android:duration="500" />
<item android:drawable="@drawable/circular10" android:duration="500" />
<item android:drawable="@drawable/circular11" android:duration="500" />
<item android:drawable="@drawable/circular1" android:duration="500" />
</animation-list>



layout main.xml



<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<LinearLayout android:id="@+id/urlBar"
android:layout_width="fill_parent"
android:layout_height="50px"
android:background="@anim/layoutanimation"
android:orientation="horizontal">

<Button android:id="@+id/start"
android:layout_width="wrap_content"
android:layout_height="50px"
android:text="start" />

<Button android:id="@+id/stop"
android:layout_width="wrap_content"
android:layout_height="50px"
android:text="stop"/>
</LinearLayout>

<ImageView android:id="@+id/img"
android:layout_width="50px"
android:layout_height="50px"/>

</LinearLayout>



frameanimation.java



import android.app.Activity;
import android.graphics.drawable.AnimationDrawable;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;

public class frameanimation extends Activity {
AnimationDrawable animation;
AnimationDrawable animation1;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
animation = new AnimationDrawable();

animation.addFrame(getResources().getDrawable(R.drawable.gradient_25), 500);
animation.addFrame(getResources().getDrawable(R.drawable.gradient_50), 500);
animation.addFrame(getResources().getDrawable(R.drawable.gradient_75), 500);
animation.addFrame(getResources().getDrawable(R.drawable.gradient_100), 500);
animation.setOneShot(false);


ViewGroup layout = (ViewGroup)findViewById(R.id.urlBar);
layout.setBackgroundDrawable(animation);

ImageView imageAnim = (ImageView) findViewById(R.id.img);
imageAnim.setBackgroundResource(R.anim.imageanimation);
animation1 = (AnimationDrawable) imageAnim.getBackground();

Button start = (Button ) findViewById(R.id.start);
start.setOnClickListener(new OnClickListener ()
{
public void onClick(View v)
{
animation.start();
animation1.start();
}

});
Button stop = (Button ) findViewById(R.id.stop);
stop.setOnClickListener(new OnClickListener ()
{
public void onClick(View v)
{
animation.stop();
animation1.stop();
}

});
}

}


2 comments:

  1. You mention on your tutorial you can use animation on widgets. So my question is how would you do it, since you can't use findViewById?? You can only use RemoteViews.

    ReplyDelete
  2. Yes true, in home screen you can only use RemoteViews to bring the animation effect.

    ReplyDelete