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 :)
Related
I am currently trying to implement tinting on some ImageButtons with currently pure white Drawables. The Tint Color should be provided by a StateList and should change depending on the buttons current state. The state list does look like:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="#FF0000"/>
<item android:color="#00FF00" android:state_enabled="false"/>
<item android:color="#0000FF" android:state_pressed="true" android:state_enabled="true"/>
</selector>
And the layout XML snippet for the button is:
<ImageButton
android:id="#+id/btnNext"
style="#style/Widget.AppCompat.Button.Borderless"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="#dimen/vertical_content_padding"
android:layout_marginEnd="#dimen/horizontal_content_padding"
android:contentDescription="#string/next"
android:src="#drawable/ic_chevron_right_white_24dp"
android:tint="#color/state_btn_tint_light"/>
The default tint from the Color State List is selected and correctly displayed. But disabling the button or pressing it doesn't trigger any color change at all of the Icon. I tried setting it pragmatically too with setImageTintList.
Your code should work. However, there is one mistake:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="#FF0000"/>
<item android:color="#00FF00" android:state_enabled="false"/>
<item android:color="#0000FF" android:state_pressed="true" android:state_enabled="true"/>
</selector>
You need to reverse the order of the states.
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="#0000FF" android:state_pressed="true" android:state_enabled="true"/>
<item android:color="#00FF00" android:state_enabled="false"/>
<item android:color="#FF0000"/>
</selector>
I am not entirely sure how it works internally but it seems to function like If/Else statements. If the first condition fails, then it goes to the second. Since your first item has no conditions, it will always be picked and the others will be ignored, giving the impression that the color state list is not working at all. Hence, always put the color state with the most restrictive conditions first.
I'm going to simplify my answer. hopefully, it helps.
You can always enter any color you want in colors.xml right? so let's use it.
you can create an integer array list of the color you want like this
integer[] colors = new integer[]{R.color.white, R.color.black, ...};
Now imageButtons can take background tint like this for example:
imagebutton.setImageTintList(ColorStateList.valueOf(ContextCompat.getColor(mContext,R.color.white)));
Now let's put them together with an animation, create animation method:
public ValueAnimator ColorAnimation(ImageButton imagebutton, int colorFrom, int colorTo){
ValueAnimator anim = ValueAnimator.ofObject(new ArgbEvaluator(), colorFrom, colorTo);
anim .addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
imagebutton.setImageTintList(ColorStateList.valueOf((int) animation.getAnimatedValue()));
}
});
anim.setInterpolator(new DecelerateInterpolator());
anim.setDuration(300); // -- Whatever time
return anim;
};
Now, in your activity, you can implement it like this:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout);
mContext = this;
...
ImageButton myButton = (ImageButton) findViewById(R.id.imagebutton);
//-- Define All the Colors You want
integer[] listOfColors = new integer[]{R.color.white, R.color.black, R.color.yellow, R.color.red, R.color.blue};
//-- With this you can randomly get a color from the list
int aColor = (int)(Math.random()*listOfColors.length);
//-- Your Default imageButton Color
int DefaultColor = ContextCompat.getColor(mContext,R.color.white);
myButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
ColorAnimation(myButton, DefaultColor, listOfColors[aColor]).start;
//-- You can even enter whatever color want directly for "colorTo"
//-- You can Reverse this animation as well
}
});
...
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();
}
}
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();
}
});
}
I am trying to get a frame by frame animation to run on android 2.2 in a 2.2 vm machine using eclipse and i cannot for the life of me get it to run. It just sits there on the first frame of the animation.
Here is my activity code:
public class SpriteAnimationActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ImageView lView = (ImageView) findViewById(R.id.imageView1);
AnimationDrawable lAnimation = (AnimationDrawable)lView.getBackground();
lAnimation.start();
}
}
Here is my animation list xml file:
<?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/a1" android:duration="100" />
<item android:drawable="#drawable/a2" android:duration="100" />
<item android:drawable="#drawable/a3" android:duration="100" />
</animation-list>
I am using the imageView widget on my main screen to display the image by setting the background. I tried to follow the guide here http://developer.android.com/guide/topics/graphics/drawable-animation.html but I can't seem to get it to work
Here you can get help:
Simple tween animation example
Android animation example on Google Code
You have to start animation forcefully...
ImageView lView = (ImageView) findViewById(R.id.imageView1);
lView.setBackgroundResource(R.drawable.my_animation_list);
final AnimationDrawable lAnimation = (AnimationDrawable)lView.getBackground();
// Button btn=
findViewById(R.id.button1).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
lAnimation.start();
}
});
You have to start the animation manually through button click listener or use the onWindowFocusChange listener like below
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if(hasFocus) {
lAnimation.start();
}
}
My Problem is I have Some Images & I used frame animation to display this images on click event of button but if i click button first time the image is display in sequence & if i click this button another time that time the image is not displayed. following is my code.
Animation.java file:-
public class Animation extends Activity {
Button mBtnOK;
AnimationDrawable frameAnimation;
ImageView imgView;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mBtnOK = (Button) findViewById(R.id.mBtnOK);
mBtnOK.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
animate();
}
});
}
private void animate() {
imgView = (ImageView) findViewById(R.id.simple_anim);
imgView.setVisibility(ImageView.VISIBLE);
imgView.setBackgroundResource(R.anim.simple_animation);
AnimationDrawable frameAnimation = (AnimationDrawable) imgView
.getBackground();
frameAnimation.start();
frameAnimation.setOneShot(true);
}
}
Animation file:-
<?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/monkey_1" android:duration="50" />
<item android:drawable="#drawable/monkey_2" android:duration="50" />
<item android:drawable="#drawable/monkey_3" android:duration="50" />
<item android:drawable="#drawable/monkey_4" android:duration="50" />
<item android:drawable="#drawable/monkey_5" android:duration="50" />
<item android:drawable="#drawable/monkey_6" android:duration="50" />
<item android:drawable="#drawable/monkey_7" android:duration="50" />
<item android:drawable="#drawable/monkey_8" android:duration="50" />
<item android:drawable="#drawable/monkey_9" android:duration="50" />
<item android:drawable="#drawable/monkey_10" android:duration="50" />
</animation-list>
The only way to restart a frame animation is to use the setVisible() which contains a flag to force the animation to reset to the first frame. If you modify the animating section of code like so:
AnimationDrawable frameAnimation = (AnimationDrawable) imgView.getBackground();
frameAnimation.setOneShot(true);
frameAnimation.setVisible(true, true);
frameAnimation.start();
The animation should always start from the first frame and run to completion each time you click the button. The animation can also be reset by toggling visibility on the drawable itself, instead of the ImageView that contains it.
HTH
#Dipak,
I have done with the animation using the same way you have done. Try to add this code, hope your error will be resolved. And also one more thing is use thread to run the animation. This will surely run it nicely.
if(frameAnimation.isRunning()) {
frameAnimation.stop();
frameAnimation.start();
}