In my app, I have a blinking play-pause button which I've made using an animation-list, as follows:
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false">
<item android:drawable="#drawable/play_pause" android:duration="750" />
<item android:drawable="#drawable/play_pause_play" android:duration="750" />
</animation-list>
Both play_pause and play_pause_play are PNG files. This animation is used (as #drawable/play_pause_ready) inside a level-list:
<?xml version="1.0" encoding="utf-8"?>
<level-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:maxLevel="1" android:drawable="#drawable/play_pause_pause" />
<item android:maxLevel="2" android:drawable="#drawable/play_pause_play" />
<item android:maxLevel="3" android:drawable="#drawable/play_pause" />
<item android:maxLevel="10" android:drawable="#drawable/play_pause_ready" />
</level-list>
and the level-list in turn is used as a compound drawable in a TextView. In case it's relevant, the code to operate it looks like this:
private void updatePlayPauseButton(...) {
if (getView() != null) {
LevelListDrawable ld = (LevelListDrawable) timeField.getCompoundDrawables()[2];
ld.setLevel(...);
Drawable child = ld.getCurrent();
if (child instanceof AnimationDrawable) {
AnimationDrawable ad = (AnimationDrawable) child;
ad.start();
}
}
}
and is called from onStart() and other places (the behaviour is the same when it's called in response to a button press).
On ICS and Jellybean, everything works perfectly, but on my HTC Desire running Froyo, the animation displays wrong. The first frame of the animation displays for roughly the right duration (750 ms), but the second frame displays for a very short period, no more than 20 ms.
This looks very much like a bug in Froyo, but I can't find anything about it on Internet. Has anyone seen this problem before, and if so, is there a workaround?
i had similar issues with animation-list on Android 2.2, 3.2
solved with AnimationDrawable.setCallback()
void startAnimation(ImageView iv) {
final AnimationDrawable ad = (AnimationDrawable) iv.getDrawable();
ad.setCallback(iv);
ad.setVisible(true, true);
iv.post(new Runnable() {
#Override public void run() {
ad.start();
}
});
}
Related
I created a custom ProgressDialog which has a lively ImageView. But this giving error for use within a AsyncTask execution.
AsyncTask out of work. I tried to use the animation with a runOnUiThread and not worked. How can I use this animation while running AsyncTask?
layout_progress.xml (only image)
<ImageView
android:id="#+id/ivLoading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#anim/loading"
android:layout_centerHorizontal="true"
android:layout_marginTop="100dp"/>
loading.xml (animation)
<?xml version="1.0" encoding="utf-8"?>
<animation-list android:id="#+id/animation" android:oneshot="false"
xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#drawable/load5_1" android:duration="150" />
<item android:drawable="#drawable/load5_2" android:duration="150" />
<item android:drawable="#drawable/load5_3" android:duration="150" />
<item android:drawable="#drawable/load5_4" android:duration="150" />
<item android:drawable="#drawable/load5_5" android:duration="150" />
<item android:drawable="#drawable/load5_6" android:duration="150" />
<item android:drawable="#drawable/load5_7" android:duration="150" />
<item android:drawable="#drawable/load5_8" android:duration="150" />
<item android:drawable="#drawable/load5_9" android:duration="150" />
<item android:drawable="#drawable/load5_10" android:duration="150" />
</animation-list>
method show of the custom progress dialog
public void show() {
super.show();
setContentView(layoutId);
final ImageView imageView = (ImageView) findViewById(R.id.ivLoading);
final AnimationDrawable anim = (AnimationDrawable) imageView.getDrawable();
final Runnable run = new Runnable() {
#Override
public void run() {
anim.start();
}
};
imageView.post(run);
//test 2 - doesnt work
/*
final Runnable run = new Runnable() {
#Override
public void run() {
anim.start();
imageView.post(this);
}
};
activity.runOnUiThread(run);
*/
}
You should not do this in an AsyncTask. Manipulation of the UI should be done only in the UI thread.
There is a simple example of what you are trying to achieve here:
http://developer.android.com/guide/topics/graphics/drawable-animation.html
Try and start the animation after you are sure that the ImageView has been attached to the view hierarchy. Quoting the link I posted:
It's important to note that the start() method called on the AnimationDrawable cannot be called during the onCreate() method of your Activity, because the AnimationDrawable is not yet fully attached to the window. If you want to play the animation immediately, without requiring interaction, then you might want to call it from the onWindowFocusChanged() method in your Activity, which will get called when Android brings your window into focus.
I am trying to create a media player and in that I want to make the Play button transform to Pause button when clicked and again transform back to Play button when clicked again. It's a .gif image which I want to play forward upon first click and play backward upon second click. There are many tutorials about how to add an image as a button in android but none of them talks about button with animation that plays upon clicking. I am sure this is supported because I have seen similar applications. I want to know what is the correct way to do this? So it's not performance expensive and also works correctly regardless of the environment. Also I would appreciate a minimal example if possible.
UPDATE:
As a real close example to what I have in mind can be the Sony Xperia (Z1 or Z Ultra models to be specific) walkman app. This is a sample image to clarify things further.
You could use an AnimationDrawable (link contains example).
I don't see a way to play it in reverse, so you'd probably create 2 of them, one with the images playing forward, one with them playing backward. In your button OnClickListener, set the drawable to one animation or the other as needed, then start() the animation.
To use this technique you'll have to convert your gif into individual frames. There are a good number of free tools you can use to do this.
Example code:
public class AnimationDrawableButtonActivity extends FragmentActivity {
private AnimationDrawable[] mAnimations;
private int mAnimationIndex = 1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_animation_drawable_button);
new LoadAnimationTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
class LoadAnimationTask extends AsyncTask<Void, Void, AnimationDrawable[]>{
#Override
protected AnimationDrawable[] doInBackground(Void... voids) {
AnimationDrawable[] animations = new AnimationDrawable[2];
animations[0] = (AnimationDrawable) getResources().getDrawable(R.drawable.play_pause);
animations[1] = (AnimationDrawable) getResources().getDrawable(R.drawable.play_pause_reverse);
animations[0].setOneShot(true);
animations[1].setOneShot(true);
return animations;
}
#Override
protected void onPostExecute(AnimationDrawable[] animationDrawables) {
super.onPostExecute(animationDrawables);
mAnimations = animationDrawables;
final ImageButton playButton = (ImageButton) findViewById(R.id.btnPlay);
playButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
mAnimationIndex = (mAnimationIndex+ 1) %2;
playButton.setImageDrawable(mAnimations[mAnimationIndex]);
mAnimations[mAnimationIndex].start();
}
});
}
}
}
play_pause.xml
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#drawable/play_pause_022" android:duration="#integer/play_pause_duration" />
<item android:drawable="#drawable/play_pause_023" android:duration="#integer/play_pause_duration" />
<item android:drawable="#drawable/play_pause_024" android:duration="#integer/play_pause_duration" />
<item android:drawable="#drawable/play_pause_025" android:duration="#integer/play_pause_duration" />
<item android:drawable="#drawable/play_pause_026" android:duration="#integer/play_pause_duration" />
</animation-list>
play_pause_reverse.xml
<animation-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#drawable/play_pause_026" android:duration="#integer/play_pause_duration" />
<item android:drawable="#drawable/play_pause_025" android:duration="#integer/play_pause_duration" />
<item android:drawable="#drawable/play_pause_024" android:duration="#integer/play_pause_duration" />
<item android:drawable="#drawable/play_pause_023" android:duration="#integer/play_pause_duration" />
<item android:drawable="#drawable/play_pause_022" android:duration="#integer/play_pause_duration" />
</animation-list>
ints.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<integer name="play_pause_duration">32</integer>
</resources>
activity_animation_drawable_button.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent">
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/btnPlay"
android:layout_gravity="center"
android:src="#drawable/play_pause_022"
style="?android:attr/buttonBarButtonStyle"
android:padding="8dp" />
</FrameLayout>
Hi I am looking to create gif animation in xml.I separated gif images and used the below code
myxm.xml
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false">
<item android:drawable="#drawable/a" android:duration="100" />
<item android:drawable="#drawable/c" android:duration="100" />
<item android:drawable="#drawable/e" android:duration="100" />
</animation-list>
and in my layout i used the code
<ImageView
android:id="#+id/imageButton1"
android:layout_width="70dp"
android:layout_height="70dp"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginTop="16dp"
android:src="#anim/myxm" />
But it doesn't works animation.Is it the right way to create gif animation in xml ? please help me thanks in advance :)
You can try the following,
AnimationDrawable frameAnimation;
ImageView view;
view = (ImageView) findViewById(R.id.imageButton1);
// Setting myxm.xml as the background of the image view
view.setBackgroundResource(R.anim.myxm);
// Typecasting the Animation Drawable
frameAnimation = (AnimationDrawable) view.getBackground();
// Called when Activity becomes visible or invisible to the user
#Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus) {
// Starting the animation when in Focus
frameAnimation.start();
} else {
// Stoping the animation when not in Focus
frameAnimation.stop();
}
}
I'm working on a project which should have a progressdialog. But since i didn't find an easy way to style a progressdialog, i was thinking, that the easiest way is to create a custom dialog class with it's own style, and a frame by frame animation on it, and show it instead. Here is my code:
The xml layout for the dialog:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#drawable/dialog_background"
android:gravity="center"
android:orientation="horizontal"
android:padding="10dp" >
<ImageView
android:id="#+id/loaddialog_animation"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/loadanimation"
android:layout_marginRight="10dp" />
<TextView
android:id="#+id/loaddialog_text"
style="#style/SmallText"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</LinearLayout>
Here is my dialog class:
public class LoadDialog extends Dialog
{
private TextView message;
ImageView image;
AnimationDrawable animation;
public LoadDialog(Context context)
{
super(context, R.style.Dialog);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.load_dialog);
message = (TextView) findViewById(R.id.loaddialog_text);
image = (ImageView) findViewById(R.id.loaddialog_animation);
image.setBackgroundResource(R.drawable.loadanimation);
animation = (AnimationDrawable) image.getBackground();
}
public void setText(String msg)
{
message.setText(msg);
}
#Override
public void show()
{
super.show();
animation.start();
}
#Override
public void dismiss()
{
animation.stop();
super.dismiss();
}
}
and the animation resource:
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="true" >
<item android:drawable="#drawable/loadbar_01" android:duration="50" />
<item android:drawable="#drawable/loadbar_02" android:duration="50" />
<item android:drawable="#drawable/loadbar_03" android:duration="50"/>
</animation-list>
The problem is that the animation doesn't starts, when i try to show it. I know, there are a lots of topics about this problem, but here are the things, that i have tried:
Put the dialogs show() in different parts of my activity: onResume() and onCreate().
onWindowFocusChanged() is not an option, since i want to show a dialog. dialog shown ->focus change, dialog dismissed->focus change ->infinite amount of dialogs shown.
I have tried animation.setCallback(image), animation.setVisible(true, true), animation.invalidateSelf() none of them works.
I have tried image.post() and put a runnable in there as a parameter, and in the run method starting the animation, no luck.
At this point i'm starting to run out of options. The I'm only trying to show 3 images changing until the dialog is dismissed. Please if you know, what am i doing wrong, or any alternative, let me know!
Thanks in advance!
Change android:oneshot="true" to android:oneshot="false" so that it repeats. It should be currently only doing one cycle and since your show time is 50, that is really fast. I would also change that to maybe 200 or so..
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false" >
<item android:drawable="#drawable/loadbar_01" android:duration="200" />
<item android:drawable="#drawable/loadbar_02" android:duration="200" />
<item android:drawable="#drawable/loadbar_03" android:duration="200"/>
</animation-list>
Also, you are setting the image in your xml layout, but animated the background, so you need to either change the xml layout to this:
<ImageView android:id="#+id/loaddialog_animation" android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/loadanimation"
android:layout_marginRight="10dp" />
or change you code to get the src file rather than the background, like this:
image = (ImageView) findViewById(R.id.loaddialog_animation);
image.set(R.drawable.loadanimation);
animation = (AnimationDrawable) image.getDrawable();
Faced the same issue today. Placing the animation.start() in the onShow() method of OnShowListener did the trick for me.
public class CustomProgressDialog extends Dialog
{
ImageView progressImage;
AnimationDrawable frameAnimation;
public CustomProgressDialog(Context context)
{
super(context);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.custom_progress);
getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
progressImage = (ImageView) findViewById(R.id.custom_progress_image);
progressImage.setBackgroundResource(R.anim.progress_anim);
frameAnimation = (AnimationDrawable) progressImage.getBackground();
OnShowListener osl = new OnShowListener()
{
#Override
public void onShow(DialogInterface dialog)
{
frameAnimation.start();
}
};
setOnShowListener(osl);
OnDismissListener odl = new OnDismissListener()
{
#Override
public void onDismiss(DialogInterface dialog)
{
frameAnimation.stop();
}
};
setOnDismissListener(odl);
}
}
I have made custom buttons in Android for a while. Things were simple, just made image resources for button states and made a selector for it. Everything went smooth and nice. Now I encountered a new situation.
I have made a animation drawable and set it as a background for my button.
<animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false">
<item android:drawable="#drawable/frame1" android:duration="600" />
<item android:drawable="#drawable/frame2" android:duration="300" />
<item android:drawable="#drawable/frame3" android:duration="500" />
</animation-list>
If I set the animation as button's Background it works fine. If I try to make a simple selector
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:state_pressed="false"
android:drawable="#drawable/animation" />
<item
android:state_pressed="true"
android:drawable="#drawable/pressed" />
</selector>
where normal state of the button would have animation as background and the pressed state a static image, things don't work right.
On my main activity, on onWindowFocus I get the button background and start the animation
#Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
btn = (Button)findViewById(R.id.btnAnim);
btnAnimation = (AnimationDrawable) btnAnim.getBackground();
btnAnimation.start();
}
Here appears to be the problem, because my animation won't be taken correctly from the selector and I get the following error:
03-14 15:21:16.146: ERROR/AndroidRuntime(440): FATAL EXCEPTION: main
03-14 15:21:16.146: ERROR/AndroidRuntime(440): java.lang.ClassCastException: android.graphics.drawable.StateListDrawable
03-14 15:21:16.146: ERROR/AndroidRuntime(440): at com.bebenjoy.MainActivity.onWindowFocusChanged(MainActivity.java:53)
03-14 15:21:16.146: ERROR/AndroidRuntime(440): at ...
Any idea on how to fix this ? Thanks.
You're doing incorrect cast -- your background drawable is StateListDrawable, not AnimationDrawable. I'd rather do something like:
#Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
btn = (Button)findViewById(R.id.btnAnim);
StateListDrawable background = (StateListDrawable) btn.getBackground();
Drawable current = background.getCurrent();
if (current instanceof AnimationDrawable) {
btnAnimation = (AnimationDrawable) current;
btnAnimation.start();
}
}
My answer is a bit late, I know, but I faced the same issue. I checked a lot of solutions, but found only one.
I have tried to start the animation in onWindowFocusChanged(), start the animation in aseparate thread, but it doesn't help.
I solved this issue using setVisible (boolean visible, boolean restart)
So you can try this:
private Button ImgBtn;
private AnimationDrawable btnAnimation;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn = (Button)findViewById(R.id.button1);
StateListDrawable background = (StateListDrawable) btn.getBackground();
btnAnimation = (AnimationDrawable) background.getCurrent();
btnAnimation.setVisible(true, true); // it works even in onCreate()
}
Hope this will help somebody :)