I am trying to animate an ImageButton. When the button is clicked, I want it to slide to the right. When it's clicked again, it should slide back to its original position.
When the animation ends it goes back to the original position therefore I reposition the ImageButton. I have a small "flash" where both the ImageButton and the animation is at the original position before the ImageButton has been repositioned. Can anyone tell me how to get rid of this "flash"?
I have written the following code to start the animations and when the animation ends, move the ImageButton itself.
What it is, is an onClickListener for sliding the ImageButton in and an AnimationListener for this. There's also an onClickListener and an AnimationListener for sliding the ImageButton back.
private class SceneIndicatorListenerIn implements ImageButton.OnClickListener {
ImageButton imageButton;
public SceneIndicatorListenerIn (ImageButton imageButton) {
this.imageButton = imageButton;
}
#Override
public void onClick(View view) {
// Create animation
Animation anim = AnimationUtils.loadAnimation(context, R.anim.sceneindicator_in);
anim.setAnimationListener(new SceneIndicatorListenerInDidEnd(imageButton));
view.startAnimation(anim);
}
}
private class SceneIndicatorListenerInDidEnd implements AnimationListener {
ImageButton imageButton;
public SceneIndicatorListenerInDidEnd (ImageButton imageButton) {
this.imageButton = imageButton;
}
#Override
public void onAnimationEnd(Animation anim) {
Log.d(LOG_TAG, "In animation did end");
// This is for density pixels
float dp = context.getResources().getDisplayMetrics().density;
// Keep position after animation
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(imageButton.getWidth(), imageButton.getHeight());
params.setMargins((int) (0 * dp), imageButton.getTop(), 0, 0);
imageButton.setLayoutParams(params);
// Change on click listener
imageButton.setOnClickListener(new SceneIndicatorListenerOut(imageButton));
}
#Override
public void onAnimationRepeat(Animation arg0) {}
#Override
public void onAnimationStart(Animation arg0) {}
}
private class SceneIndicatorListenerOut implements ImageButton.OnClickListener {
ImageButton imageButton;
public SceneIndicatorListenerOut (ImageButton imageButton) {
Log.d(LOG_TAG, "My imageButton was set");
this.imageButton = imageButton;
}
#Override
public void onClick(View view) {
Log.d(LOG_TAG, "You clicked me");
// Create animation
Animation anim = AnimationUtils.loadAnimation(context, R.anim.sceneindicator_out);
anim.setAnimationListener(new SceneIndicatorListenerOutDidEnd(imageButton));
view.startAnimation(anim);
}
}
private class SceneIndicatorListenerOutDidEnd implements AnimationListener {
ImageButton imageButton;
public SceneIndicatorListenerOutDidEnd (ImageButton imageButton) {
this.imageButton = imageButton;
}
#Override
public void onAnimationEnd(Animation anim) {
Log.d(LOG_TAG, "Out animation did end");
// This is for density pixels
float dp = context.getResources().getDisplayMetrics().density;
// Keep position after animation
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(imageButton.getWidth(), imageButton.getHeight());
params.setMargins((int) (-199 * dp), imageButton.getTop(), 0, 0);
imageButton.setLayoutParams(params);
// Change on click listener
imageButton.setOnClickListener(new SceneIndicatorListenerIn(imageButton));
}
#Override
public void onAnimationRepeat(Animation arg0) {}
#Override
public void onAnimationStart(Animation arg0) {}
}
This is my animation for sliding in:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromXDelta="0%"
android:toXDelta="83%"
android:duration="750" />
</set>
And this is my animation for sliding back:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromXDelta="0%"
android:toXDelta="-80%"
android:duration="750" />
</set>
I had this same issue and wanted to post the answer for anyone who encounters this. There is a bug that causes this no matter what you set in xml or otherwise.
The way I got around it was the manually set the X location off of the screen before the animation so that the flash would happen off of the screen, then it would be set back to it's original position as being processed by the animation.
image.setX(-5000);//Really any number off of the screen will do
Animation animation0 = AnimationUtils.loadAnimation(this,
R.anim.slide_across_right);
animation0.setAnimationListener(new AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
animationHack();
}
#Override
public void onAnimationRepeat(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
}
});
private void animationHack() {
(new Handler()).postDelayed(new Runnable() {
public void run() {
image.setX(0);
}
}, 20);
}
Related
public class MainActivity extends Activity {
ValueAnimator animator;
ImageButton testImageButton;
float rad=1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
testImageButton = findViewById(R.id.ib_test);
testImageButton.setOutlineProvider(outlineProvider);
testImageButton.setClipToOutline(true);
animator = (ValueAnimator)
AnimatorInflater.loadAnimator(this,R.animator.radius);
animator.addUpdateListener(mListener);
}
public void clickedAnimator(View v){
animator.start();
}
public void testMe(View v){
l("testMe");
}
ValueAnimator.AnimatorUpdateListener mListener = new
ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
float i= (float) valueAnimator.getAnimatedValue();
rad = i;
testImageButton.setOutlineProvider(outlineProvider);
}
};
ViewOutlineProvider outlineProvider = new ViewOutlineProvider() {
#Override
public void getOutline(View view, Outline outline) {
outline.setRoundRect(0,0,view.getWidth(),view.getHeight(),
rad*((float)view.getWidth())/2);
}
};
public void l(String s){
Log.v(getClass().getSimpleName(),s);
}
}
I am trying to animate the outline of an ImageView from Circle to Rectangle by constantly updating the ViewOutlineProvider that is set to the imageview.
Everything works fine but when the animation ends, the Image in the imageView Blinks once.
The value of rad changes from 1 to 0 in 500ms.
Hmmm, this line might help you: android:fillAfter="true"
Place this in your animation XML file inside the set attribute like:
<set [...]
android:fillAfter="true">
This helped me on a number of occasions when the animation was bugging at the end. Might work for you, might not, it's worth trying.
I have repeatedly defined animation in this code. Is not there a simpler way to do this? the code works the way I want it, but I want to simplify my encoding.can you help me. How should I follow a method. How to add wait time?
I made a code that I could not do in this title but it came to be written much shorter
resimyukle();
hediye=getDrawable(R.drawable.hediye);
final ImageView[] imajlar={img1,img2,img3,img4,img5,img6,img7,img8};
Animation fadein=AnimationUtils.loadAnimation(getApplicationContext(),R.anim.fadein);
imajlar[0].setBackground(hediye);
imajlar[0].startAnimation(fadein);
Animation res=AnimationUtils.loadAnimation(getApplicationContext(),R.anim.fadein);
Animation res1=AnimationUtils.loadAnimation(getApplicationContext(),R.anim.fadein);
Animation res2=AnimationUtils.loadAnimation(getApplicationContext(),R.anim.fadein);
Animation res3=AnimationUtils.loadAnimation(getApplicationContext(),R.anim.fadein);
Animation res4=AnimationUtils.loadAnimation(getApplicationContext(),R.anim.fadein);
Animation res5=AnimationUtils.loadAnimation(getApplicationContext(),R.anim.fadein);
Animation res6=AnimationUtils.loadAnimation(getApplicationContext(),R.anim.fadein);
anima(fadein,res,imajlar[1]);
anima(res,res1,imajlar[2]);
anima(res1,res2,imajlar[3]);
anima(res2,res3,imajlar[4]);
anima(res3,res4,imajlar[5]);
anima(res4,res5,imajlar[6]);
anima(res5,res6,imajlar[7]);
}
public void anima(final Animation aa, final Animation bb, final ImageView img)
{
aa.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
animation.cancel();
img.setBackground(hediye);
img.startAnimation(bb);
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
}
hediye=getDrawable(R.drawable.hediye);
final ImageView[] imajlar={img1,img2,img3,img4,img5,img6,img7,img8};
Animation res=AnimationUtils.loadAnimation(getApplicationContext(),R.anim.fadein);
for (int i = 0; i < imajlar.size; i++) {
anima(res, imajlar[i], i);
}
And your method:
public void anima(Animation aa, ImageView img, int id)
{
aa.setStartOffset(id * 500);
aa.setDuration(1000);
img.startAnimation(aa);
img.setBackground(hediye);
}
I want to implement zoom feature on an ImageButton by Property Animation. For example, when I click the button, it will zoom out. And when I click it again, it will zoom in.
Here is part of my code:
OnClickListener clickPlayButtonHandler = new OnClickListener() {
#Override
public void onClick(View v) {
final ImageButton clickedButton = (ImageButton) v;
if((Boolean) v.getTag()) {
// zoom out
clickedButton.animate().setInterpolator(new AnticipateInterpolator()).setDuration(500).scaleXBy(-0.4f).scaleYBy(-0.4f).setListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animation) {
clickedButton.setImageResource(R.drawable.bg_pause);
System.out.println(clickedButton.getWidth()); // output the width of the button for checking
}
#Override
public void onAnimationEnd(Animator animation) {
clickedButton.setTag(false);
int d = clickedButton.getWidth();
System.out.println(clickedButton.getWidth());// output the width of the button for checking
}
#Override
public void onAnimationCancel(Animator animation) {}
#Override
public void onAnimationRepeat(Animator animation) { }
});
} else {
// process zoom in
}
}
};
I printed the width of the button before the animation start and the animation finished. However, I found they were the same. I thought when the zoom out animation finished the button width should be small than before. But it didn't.
Could not change view size by ViewPropertyAnimator?
There won't be changes in clickedButton.getWidth(), because the width of a view is not affected by scaling. You can think of getWidth() as a way to get unscaled width of a view. To change the width of a View requires a new measure/layout pass.
ViewPropertyAnimator doesn't change View's width/height or anything that could potentially trigger another layout pass. This is simply because layout passes are expensive and therefore could cause frame skipping, which is the last thing we want see during an Animation.
If you need to get scaled width of the button, you can do getScaleX() * clickedButton.getWidth()
Try the ObjectAnimator:
ObjectAnimator xAnimator =
ObjectAnimator.ofFloat(clickedButton, "scaleX", 1.0f, -0.4f);
ObjectAnimator yAnimator =
ObjectAnimator.ofFloat(clickedButton, "scaleY", 1.0f, -0.4f);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.setDuration(500);
animatorSet.playTogether(xAnimator, yAnimator);
animatorSet.setInterpolator(new AnticipateInterpolator());
animatorSet.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animation) {
clickedButton.setImageResource(R.drawable.bg_pause);
System.out.println(clickedButton.getWidth());
}
#Override
public void onAnimationEnd(Animator animation) {
clickedButton.setTag(false);
int d = clickedButton.getWidth();
System.out.println(clickedButton.getWidth());
}
#Override
public void onAnimationCancel(Animator animation) {
}
#Override
public void onAnimationRepeat(Animator animation) {
}
});
animatorSet.start();
I am working on a project that must work on Android 2.2 onwards, and I just realized I was using a 3.0+ method from View.
I have a menu that animates vertically sliding in/out when a button is pressed. When the animation finishes I update the View position with setY() method.
I tried to change it to getTop/setTop but it's not working properly, I suspect because getY is actually taking into account transformations and getTop is not (I guess animations are handled as transformations).
Any easy alternative for Froyo without modifying too much code?
This is the animation part:
animationSlideInDown = AnimationUtils.loadAnimation(this, R.anim.slide_out_down);
animationSlideOutUp = AnimationUtils.loadAnimation(this, R.anim.slide_in_up);
animationSlideInDown.setDuration(200);
animationSlideOutUp.setDuration(200);
animationSlideInDown.setAnimationListener(new AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
if (menuInitialPosition == -1) {
menuInitialPosition = menu.getY();
menuHeight = menu.getHeight();
} else {
menu.setY(menuInitialPosition);
}
}
#Override
public void onAnimationRepeat(Animation animation) {}
#Override
public void onAnimationEnd(Animation animation) {
menu.setY(menuInitialPosition);
}
});
animationSlideOutUp.setAnimationListener(new AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {}
#Override
public void onAnimationRepeat(Animation animation) {}
#Override
public void onAnimationEnd(Animation animation) {
menu.setY(-menuHeight);
}
});
This is the slide_out transition:
<translate
xmlns:android="http://schemas.android.com/apk/res/android"
android:fromYDelta="-100%"
android:toYDelta="0"
android:fillAfter="true"
android:fillEnabled="true"
android:duration="#android:integer/config_longAnimTime" />
Thanks!
If you want to get position of particular view on the screen than you can use :
int[] locationOnScreen = new int[2];
menu.getLocationOnScreen(locationOnScreen);
And for setting view to particular position you can use LayoutParams and set left and top margin for the view.
I am animating a view using translate animation. I've used setFillAfter(true) and it animates successfully.
My code is.
final ImageView image= (ImageView) findViewById(R.id.image2);
image.setBackgroundResource(R.drawable.lamb);
final Animation animation = AnimationUtils.loadAnimation(this, R.anim.translate);
animation.setFillAfter(true);
image.startAnimation(animation);
animation.setAnimationListener(new AnimationListener()
{
public void onAnimationStart(Animation animation) { }
public void onAnimationRepeat(Animation animation) { }
public void onAnimationEnd(Animation animation)
{
Handler ss = new Handler();
ss.postDelayed(new Runnable()
{
public void run()
{
image.setVisibility(View.INVISIBLE);
}
} ,4000);
}
});
I use a Handler for hiding the image view after 4 seconds, but it does not hide. How can I hide the image after some time?
After the animation ends, I want to show the image on the last position that it was so I use setFillAfter(true); after 4 seconds I hide the image view.
How can I make the image invisible?
You will need to set AnimationListener. And when animation will end, make the view invisible.
moveForward.setAnimationListener(new AnimationListener(){
#Override
public void onAnimationEnd(Animation animation) {
view.setVisibility(View.INVISIBLE);
}
#Override
public void onAnimationRepeat(Animation animation) {
}
#Override
public void onAnimationStart(Animation animation) {
}
});
image.clearAniamtion(), before setVisibility(View.INVISIBLE)