170

I want to have a 2 second animation of an ImageView that spends 1000ms fading in and then 1000ms fading out.

Here's what I have so far in my ImageView constructor:

Animation fadeIn = new AlphaAnimation(0, 1);
fadeIn.setDuration(1000);

Animation fadeOut = new AlphaAnimation(1, 0);
fadeOut.setStartOffset(1000);
fadeOut.setDuration(1000);

AnimationSet animation = new AnimationSet(true);
animation.addAnimation(fadeIn);
animation.addAnimation(fadeOut);
this.setAnimation(animation);

When I run that animation, nothing shows up. However, when I remove one of the alpha animations, the behavior works as expected.

Things I have already tried:

  • Every conceivable combination of setFillBefore, setFillAfter, and setFillEnabled.
  • Adding a LinearInterpolator to the AnimationSet.
Ziem
  • 6,579
  • 8
  • 53
  • 86
plowman
  • 13,335
  • 8
  • 53
  • 53
  • 1
    Yes you can fade images in and out! This tutorial should do the trick. http://sankarganesh-info-exchange.blogspot.com/2011/04/performing-animation-in-android.html – Adam Storm Jul 22 '11 at 22:40
  • That tutorial describes a method using XML. Do you know how to achieve the same thing using Java? – plowman Jul 23 '11 at 00:30
  • Well, Im not next to my programming computer so I cant test this code, but you can set xml attributes in java. this is the original code: android:interpolator="@android:anim/accelerate_interpolator" android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="300" /> \n so you can probably MyTween.setDurationg(300) MyTween.fromAlpha(0.0) MyTween(1.0) – Adam Storm Jul 23 '11 at 17:27

12 Answers12

291

Figured out my own problem. The solution ended up being based in interpolators.

Animation fadeIn = new AlphaAnimation(0, 1);
fadeIn.setInterpolator(new DecelerateInterpolator()); //add this
fadeIn.setDuration(1000);

Animation fadeOut = new AlphaAnimation(1, 0);
fadeOut.setInterpolator(new AccelerateInterpolator()); //and this
fadeOut.setStartOffset(1000);
fadeOut.setDuration(1000);

AnimationSet animation = new AnimationSet(false); //change to false
animation.addAnimation(fadeIn);
animation.addAnimation(fadeOut);
this.setAnimation(animation);


If you are using Kotlin

val fadeIn = AlphaAnimation(0f, 1f)
fadeIn.interpolator = DecelerateInterpolator() //add this
fadeIn.duration = 1000

val fadeOut = AlphaAnimation(1f, 0f)
fadeOut.interpolator = AccelerateInterpolator() //and this
fadeOut.startOffset = 1000
fadeOut.duration = 1000

val animation = AnimationSet(false) //change to false
animation.addAnimation(fadeIn)
animation.addAnimation(fadeOut)
this.setAnimation(animation)
Leonardo Sibela
  • 1,613
  • 1
  • 18
  • 39
plowman
  • 13,335
  • 8
  • 53
  • 53
  • 1
    What if you want to do 5 or 6 fading in/out, with really small delays like 100 for each, could you use something like this ? I tried but it's not really fluid. The aim was to simulate for example a bulb that would not work properly, and twinkle. – Chayy Aug 12 '11 at 16:36
  • try and call this.setAnimation in a loop – Jono Jul 30 '13 at 15:00
  • I was thinking I fade out last bg img and fad in the current one, but this answer inspires me that I only need to fade in the current bg img and fade out the current one, cause AlphaAnimation can't fadein/out two different imgs. – macio.Jun Feb 03 '14 at 18:20
  • 9
    I don't think you need to have two independent animations... I think you could have a single animation and set the parameter: fadeInOut.setRepeatMode(Animation.REVERSE); – RoundSparrow hilltx Sep 30 '14 at 14:03
  • Second: if you wanted to repeat, no need to call in a loop like @jonney said. use fadeInOut.setRepeatCount(6) - change 6 to be how many you wish it to repeat. Much less overhead to let the native C++ code in Android do all this instead of calling in a Java loop. – RoundSparrow hilltx Sep 30 '14 at 14:04
  • This was really useful, In case you like this same effect but purely on xml check my [answer](https://stackoverflow.com/a/50035858/3908170) – DarkCygnus Apr 26 '18 at 07:21
  • On the second line, I believe there should be `AccelerateInterpolator` used as well, since you are going from alpha 0 to 1. – Firzen Feb 11 '20 at 10:38
164

I know that this already has been answered but.....

<?xml version="1.0" encoding="utf-8"?> 
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromAlpha="1.0" 
    android:toAlpha="0.0" 
    android:duration="1000"    
    android:repeatCount="infinite" 
    android:repeatMode="reverse"
    />

Quick and easy way to quickly do a fade in and out with a self repeat. Enjoy

EDIT : In your activity add this:

yourView.startAnimation(AnimationUtils.loadAnimation(co‌​ntext, R.anim.yourAnimation));
Blue Bot
  • 2,278
  • 5
  • 23
  • 33
Konrad Winkowski
  • 2,022
  • 1
  • 13
  • 15
  • 8
    +1 Because with this answer I could make a secuence of fade in, fade out and fade in (just setting repeatCount="2"). I couldn't concatenating animations as the accepted answer proposes. – ElYeante Feb 10 '14 at 14:50
  • 1
    After declaring this `alpha` resource how can I use it?. Thanks – zozelfelfo Mar 17 '14 at 12:00
  • 1
    zozelfelfo it is just a animation xml so load it into code and then call startAnimation on whatever view you want it to affect. – Konrad Winkowski Mar 18 '14 at 13:53
  • @KonradWinkowski startAnimation method requires Animation object as argument! what should i pass to it? – Ahmad Vatani Jul 24 '15 at 07:48
  • For those looking for a more complete answer: `viewToAnimate.startAnimation(AnimationUtils.loadAnimation(context, R.anim.fade_in_out)`, where there is a fade_in_out.xml file in the anim folder under res. – Chris Knight Oct 10 '17 at 22:50
39
viewToAnimate.animate().alpha(1).setDuration(1000).setInterpolator(new DecelerateInterpolator()).withEndAction(new Runnable() {
    @Override
    public void run() {
        viewToAnimate.animate().alpha(0).setDuration(1000).setInterpolator(new AccelerateInterpolator()).start();
    }
}).start();
Vitaly Zinchenko
  • 4,871
  • 5
  • 36
  • 52
  • 4
    Elegante for Marshmallow! – Eddie Feb 26 '16 at 17:03
  • 1
    An important point to note is that you need to reset the `setStartDelay()` to 0 in the first animation if you are using it in the second animation to delay its start. Else it remembers that delay for any subsequent animation. – zkon Aug 19 '20 at 04:34
28

Here is my solution using AnimatorSet which seems to be a bit more reliable than AnimationSet.

// Custom animation on image
ImageView myView = (ImageView)splashDialog.findViewById(R.id.splashscreenImage);

ObjectAnimator fadeOut = ObjectAnimator.ofFloat(myView, "alpha",  1f, .3f);
fadeOut.setDuration(2000);
ObjectAnimator fadeIn = ObjectAnimator.ofFloat(myView, "alpha", .3f, 1f);
fadeIn.setDuration(2000);

final AnimatorSet mAnimationSet = new AnimatorSet();

mAnimationSet.play(fadeIn).after(fadeOut);

mAnimationSet.addListener(new AnimatorListenerAdapter() {
    @Override
    public void onAnimationEnd(Animator animation) {
        super.onAnimationEnd(animation);
        mAnimationSet.start();
    }
});
mAnimationSet.start();
TWilly
  • 4,863
  • 3
  • 43
  • 73
24

Another alternative:

No need to define 2 animation for fadeIn and fadeOut. fadeOut is reverse of fadeIn.

So you can do this with Animation.REVERSE like this:

AlphaAnimation alphaAnimation = new AlphaAnimation(0.0f, 1.0f);
alphaAnimation.setDuration(1000);
alphaAnimation.setRepeatCount(1);
alphaAnimation.setRepeatMode(Animation.REVERSE);
view.findViewById(R.id.imageview_logo).startAnimation(alphaAnimation);

then onAnimationEnd:

alphaAnimation.setAnimationListener(new Animation.AnimationListener() {
    @Override
        public void onAnimationStart(Animation animation) {
            //TODO: Run when animation start
        }

        @Override
        public void onAnimationEnd(Animation animation) {
            //TODO: Run when animation end
        }

        @Override
        public void onAnimationRepeat(Animation animation) {
            //TODO: Run when animation repeat
        }
    });
MarsPeople
  • 1,772
  • 18
  • 30
17

As I believe in the power of XML (for layouts), this is the equivalent for the accepted answer, but purely as an animation resource:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:interpolator/accelerate_decelerate"
    android:fillAfter="true">
    <alpha
        android:fromAlpha="0"
        android:toAlpha="1"
        android:duration="1000" />
    <alpha
        android:fromAlpha="1"
        android:toAlpha="0"
        android:duration="1000"
        android:startOffset="1000"/>
</set>

The fillAfter is for the fade to remain after completing the animation. The interpolator handles interpolation of the animations, as you can guess. You can also use other types of interpolators, like Linear or Overshoot.

Be sure to start your animation on your view:

yourView.startAnimation(AnimationUtils.loadAnimation(co‌​ntext, R.anim.fade));
DarkCygnus
  • 7,420
  • 4
  • 36
  • 59
11

Here is what I used to fade in/out Views, hope this helps someone.

private void crossFadeAnimation(final View fadeInTarget, final View fadeOutTarget, long duration){
    AnimatorSet mAnimationSet = new AnimatorSet();
    ObjectAnimator fadeOut = ObjectAnimator.ofFloat(fadeOutTarget, View.ALPHA,  1f, 0f);
    fadeOut.addListener(new Animator.AnimatorListener() {
        @Override
        public void onAnimationStart(Animator animation) {
        }

        @Override
        public void onAnimationEnd(Animator animation) {
            fadeOutTarget.setVisibility(View.GONE);
        }

        @Override
        public void onAnimationCancel(Animator animation) {
        }

        @Override
        public void onAnimationRepeat(Animator animation) {
        }
    });
    fadeOut.setInterpolator(new LinearInterpolator());

    ObjectAnimator fadeIn = ObjectAnimator.ofFloat(fadeInTarget, View.ALPHA, 0f, 1f);
    fadeIn.addListener(new Animator.AnimatorListener() {
        @Override
        public void onAnimationStart(Animator animation) {
            fadeInTarget.setVisibility(View.VISIBLE);
        }

        @Override
        public void onAnimationEnd(Animator animation) {}

        @Override
        public void onAnimationCancel(Animator animation) {}

        @Override
        public void onAnimationRepeat(Animator animation) {}
    });
    fadeIn.setInterpolator(new LinearInterpolator());
    mAnimationSet.setDuration(duration);
    mAnimationSet.playTogether(fadeOut, fadeIn);
    mAnimationSet.start();
}
11

If you use Animator for make animation you can

anim (directory) -> fade_out.xml

<?xml version="1.0" encoding="UTF-8"?>
<objectAnimator
    android:propertyName="alpha"
    android:valueFrom="0"
    android:valueTo="1"
    xmlns:android="http://schemas.android.com/apk/res/android"/>

In java

Animator animator = AnimatorInflater.loadAnimator(context, R.animator.fade_out);
animator.setTarget(the_view_you_want_to_animation);
animator.setDuration(1000);
animator.start();

Other way to make animation fade out with only java code is

ObjectAnimator fadeOut = ObjectAnimator.ofFloat(the_view_you_want_to_animation, "alpha",  1f, 0);
fadeOut.setDuration(2000);
fadeOut.start();
Linh
  • 57,942
  • 23
  • 262
  • 279
10

AnimationSets don't appear to work as expected at all. In the end I gave up and used the Handler class's postDelayed() to sequence animations.

Richard
  • 1,803
  • 17
  • 17
4

You can also use animationListener, something like this:

fadeIn.setAnimationListener(new AnimationListener() {
    @Override
    public void onAnimationEnd(Animation animation) {
        this.startAnimation(fadeout);
    }
});
Ziem
  • 6,579
  • 8
  • 53
  • 86
Omid Aminiva
  • 667
  • 5
  • 14
4

I really like Vitaly Zinchenkos solution since it was short.

Here is an even briefer version in kotlin for a simple fade out

viewToAnimate?.alpha = 1f
viewToAnimate?.animate()
             ?.alpha(0f)
             ?.setDuration(1000)
             ?.setInterpolator(DecelerateInterpolator())
             ?.start()
Marc
  • 1,159
  • 17
  • 31
0

Here is another alternative in Kotlin

Done progamatically using ObjectAnimator

  • Uses only one animation

  • Does not muck with the animation listeners

    private fun getFadeAnimation(v: View?): ObjectAnimator 
      return ObjectAnimator.ofFloat(v, "alpha", .3f, 1f).apply {
          repeatCount = ObjectAnimator.INFINITE
          repeatMode = ObjectAnimator.REVERSE
          duration = 1000
      }
    }
    

Create only one instance in the activity and then use:

val animator = getFadeAnimator(myView)
animator.start()
animator.end()