I'm trying to fade out an ImageView using an animation. The animation runs, fading out the ImageView, but then the image goes back to fully opaque. Why does this happen?
private void fadeOutImage() {
final ImageView imageView = (ImageView) activity.findViewById(R.id.imageView);
imageView.startAnimation(AnimationUtils.loadAnimation(activity, R.anim.fadeout));
}
I tried setting the alpha to zero as below, but then the image never showed up period. Why not?
private void fadeOutImage() {
final ImageView imageView = (ImageView) activity.findViewById(R.id.imageView);
imageView.setAlpha(0);
imageView.startAnimation(AnimationUtils.loadAnimation(activity, R.anim.fadeout));
}
To get this to work, I had to create an AnimationListener, overload the onAnimationEnd, and set the alpha to be zero there. Why?
final ImageView imageView = (ImageView) activity.findViewById(id);
Animation animation = AnimationUtils.loadAnimation(activity, R.anim.fadeout);
animation.setAnimationListener(new AnimationListener() {
#Override public void onAnimationStart(Animation animation) {
imageView.setAlpha(255);
}
#Override public void onAnimationRepeat(Animation animation) { }
#Override public void onAnimationEnd(Animation animation) {
imageView.setAlpha(0);
}
});
imageView.startAnimation(animation);
Animation XML:
<alpha
android:duration="1500"
android:fromAlpha="1.0"
android:interpolator="#android:anim/accelerate_interpolator"
android:toAlpha="0.0" />
When you start an animation, it literally takes whatever the view currently looks like, animates it according to your supplied animation, but doesn't ever actually change the state of the view.
This can get confusing, but in your first case, after the animation ends, the ImageView just goes back to whatever it looked like before the animation - in your case, the normal opaque.
In your second example, you are setting the alpha to zero before the animation starts, and so when the animation begins playing, the image is already invisible, and so it animates this invisible ImageView - which you can't see.
Therefore, the required sequence is to start the animation before changing the ImageView at all, let it play out, and then the moment the animation ends, change the state of the ImageView so that it disappears before it gets redrawn in it's original state. This is what overriding onAnimationEnd() does.
So, to recap, in the proper implementation, there are two things that affect how the ImageView gets drawn:
The animation, which affects how the ImageView looks only while the animation is playing.
The imageView.setAlpha(0); method call, to keep the image invisible once the animation finishes.
Note: to possibly increase performance, I'd suggest using
imageView.setVisibility(View.INVISIBLE);
instead of imageView.setAlpha(0);
I'm trying to fade out an ImageView using an animation. The animation runs, fading out the ImageView, but then the image goes
back to fully opaque. Why does this happen?
The animation's effects are temporary. Once the animation has completed, the view returns to its state before the animation began.
I tried setting the alpha to zero as below, but then the image never
showed up period. Why not?
Though apparently undocumented, the fromAlpha and toAlpha parameters appear to act in a multiplicative fashion. 100% of zero is still zero. I verified this by starting the alpha to a very low value, and I could see that the animation caused the alpha to start at the low value and fade to transparent.
To get this to work, I had to create an AnimationListener, overload
the onAnimationEnd, and set the alpha to be zero there. Why?
Since the animation's effects are temporary, you need to set the object to be transparent after the animation. You also have to make sure you reset the object to be opaque before you start the animation.
It looks like you can use an ObjectAnimator starting in API 11 to set the alpha (or any other property's) values directly using rather than multiplicatively.
Related
I'm building the design of an app I'm developing, and I'm trying to get an image to fade into the screen. However, the image remains invisible while it translates successfully. This is the code:
facebookLoginButton = (ImageView)findViewById(R.id.facebookLoginButton); // Start of facebookLoginButton code
facebookLoginButton.setTranslationY(250f);
facebookLoginButton.setImageAlpha(0);
facebookLoginButton.animate().translationYBy(-250f).alpha(1).setDuration(1500); // End of facebookLoginButton code
I know that the image moves successfully because when I remove the facebookLoginButton.setImageAlpha(0);, I see the image moving into the screen. How come the image stays invisible?
Note: There's no functionality to the app yet, which is why my button is an ImageView.
The ViewPropertyAnimator returned by View.animate() follows the builder pattern. Each of the methods return the pending ViewPropertyAnimator, you must call start() to activate the animation.
Edit: The alpha is also not animating because setImageAlpha() sets the alpha value for the image within the View, not the View itself. While ViewPropertyAnimator animates the alpha of the View, not the image within the View. Although ImageView.setAlpha(int alpha) is deprecated, View.setAlpha(float alpha) is not, and you must use this method to set the alpha for the View. Then ViewPropertyAnimator can animate that value:
facebookLoginButton.setTranslation(250F);
facebookLoginButton.setAlpha(0.0F);
facebookLoginButton.animate()
.translationYBy(-250F)
.alpha(1.0F)
.setDuration(1500)
.start();
I wanted to animate changing height of a TextView from 0 to its real height. I'm using this code:
ValueAnimator anim = ValueAnimator.ofInt(0, height)
.setDuration(1000);
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
public void onAnimationUpdate(ValueAnimator animation) {
textView.getLayoutParams().height = (int)animation.getAnimatedValue();
textView.requestLayout();
}
});
anim.start();
But the animation is not that smooth (not awful, but I think it can be smoother).
What are the ways to make the smoothest animations of this sort?
The reason for its not smooth is because you are setting layout height in each update call and requesting layout too which can be cpu intensive when done several times in a second. The more smoother way i can suggest is Keeping the textview visibility as gone and then setting it to visible in code.
Then you can animate the transition using animation set. Also if you dont want to customise the animation and only want it to animate into position you can use default animation by specifying below xml attribute to the parent layout of your textview
android:animateLayoutChanges= "true"
Then when you set Visibility as visible in your code like below
textview.setVisibility(View.VISIBLE)
Your textview will automatically animate into its place.
Try the below codes. I hope it will help you.
textView.setScaleY(0);
textView.setScaleX(0);
textView.animate()
.scaleY(1)
.scaleX(1)
.setDuration(200)
.setInterpolator(INTERPOLATOR)
.start();
Declare INTERPOLATOR as a class level variable like below code.
private static final Interpolator INTERPOLATOR = new DecelerateInterpolator();
This will give you a very smooth animation. And you can play with this piece of code and can animate as you need.You can change the INTERPOLATOR.
Learn more about INTERPOLATOR.
I need to scroll a TextView to the bottom till it's gone by preforming an animation like translate animation in xml. I tried to create an animation file and used translate attributes in the xml, but what it will do is that it will go down by a specific distance that I set in the xml. I don't know how to let it translate to the bottom till it's gone and disappeared from the screen. One more thing is that I also want something like a listener that will perform some action when that TextView is gone and disappeared from the screen when the animation ends.
Any suggestions will be greatly appreciated. Thanks.
You can calculate the distance you want your view to travel, but if you don't want to be exact, you can just use the screen height:
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int screenHeight = size.y;
And then just animate the view as needed, but add a listener to do what you want at the end:
textView.animate().translationY(screenHeight).setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
textView.setVisibility(View.GONE);
}
});
You still need to make the view visibility GONE at the end in the listener, just to make sure you don't see it anymore.
You can also try and use getBottom() for the distance.
In my Android app, I have a TextView with a white background. When it is clicked, its background will change to a .png picture of some icon by calling setBackgroundResource(R.drawable.icon) on the TextView. This works as intended, but the change is rather abrupt. I would like to make the icon appear more gradually; when the TextView is clicked, a tiny version of the icon should appear in the center of the TextView and then immediately expand and fill out the entire TextView. I believe the best way to do this would be by using an animation, which of the available animation types in Android are best for this task?
In case it is not clear what I mean, I drew a sketch to illustrate. The second sequence shows how the code works right now, the first shows how I would like it to be.
So, I managed to get the effect you want with an ImageView, using ScaleAnimation. Here's what you have to do:
First, our XML ImageView:
<ImageView
android:id="#+id/scale_anim"
android:layout_width="60dp"
android:layout_height="60dp"
android:background="#android:color/white" />
It has fixed dimensions and a white background.
The animation will start with one click with this, inside your onCreate() method:
ImageView starImageView = (ImageView) findViewById(R.id.scale_anim);
starImageView.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
ScaleAnimation starScaleAnimation =
new ScaleAnimation(0.3f, 1f, 0.3f, 1f,
ScaleAnimation.RELATIVE_TO_SELF, 0.5f,
ScaleAnimation.RELATIVE_TO_SELF, 0.5f);
starScaleAnimation.setDuration(500);
((ImageView) v).setImageResource(R.drawable.star);
ScaleAnimation scaleAnim = starScaleAnimation;
v.startAnimation(scaleAnim);
}
});
We are applying a scale animation on the ImageView that stars with 30% of the original size and scales to 100% of its size, from its center point. The duration of this animation is half a second. All these parameters can be changed.
Every time you click the ImageView, your drawable will be applied and the animation will start.
Try this way if it solve yours.
Create an ImageView (X) above your original ImageView (A) - same size and same place as (A)
Animate (X) with ObjectAnimator, listen for the onAnimationEnd call and set the (A)'s background. Then remove (X).
Hope this will help.
Is there a way to force an android view to redraw it's background?
I have set a drawable shape with a gradient as background which works fine but after changing the view's height you can see those ugly gradient steps.
What can I do?
I tried view.invalidate() and view.refreshDrawableState() without any visible difference.
Thank you!
//EDIT:
Here are some more details and my code:
After your answers I think the banding is a result of my probably bad code. Here is what I'm doing:
Scaling a view
setting its new width and height because the scaled view does not accept user input in other areas then the "old" one (see android weird (at least for me) behaviour of control after scaling / doesn't accept input in it's whole area )
trying to set the background again (which contains a gradient and a rectangle with rounded corners)
Here is my code:
public void onAnimationEnd(Animation animation)
{
MyView view = (MyView) ((ExtendedScaleAnimation) animation).getView();
view.getLayoutParams().width = toWidth;
view.getLayoutParams().height = toHeight;
view.clearAnimation();
view.requestLayout();
view.refreshBackground(); // background will be changed
}
On the device you can see that the background drawable is changed but there is a flickering which seems to me like the backround change is applied before the animation is over. Programatically it should be over! Or am I wrong?
Thank you again!
Can you try after resize:
v.setBackgroundResource(null);
v.setBackgroundResource(...my drawable...);