91 votes

Fondu-enchaîné Android avec ImageView

J'ai quelques problèmes avec un diaporama que je suis en train de construire.

J'ai créé 2 animations en xml pour le fondu entrant et le fondu sortant :

fadein.xml

    <?xml version="1.0" encoding="UTF-8"?>
       <set xmlns:android="http://schemas.android.com/apk/res/android">
         <alpha android:fromAlpha="0.0" android:toAlpha="1.0" 
          android:interpolator="@android:anim/accelerate_interpolator" 
          android:duration="2000"/>
     </set>

fadeout.xml

    <?xml version="1.0" encoding="UTF-8"?>
       <set xmlns:android="http://schemas.android.com/apk/res/android">
         <alpha android:fromAlpha="1.0" android:toAlpha="0.0" 
          android:interpolator="@android:anim/accelerate_interpolator" 
          android:duration="2000"/>
     </set>

Ce que j'essaie de faire, c'est de changer d'image à partir d'un ImageView en utilisant l'effet de fondu, de sorte que l'image actuellement affichée disparaisse et qu'une autre apparaisse. Considérant que j'ai une image déjà définie, je peux faire disparaître cette image sans problème, avec ceci :

    Animation fadeInAnimation = AnimationUtils.loadAnimation(this, R.anim.your_fade_in_anim);
    imageView.startAnimation(fadeoutAnim);

Mais ensuite, je règle l'image suivante à afficher :

    imageView.setImageBitmap(secondImage);

Elle s'affiche juste dans l'imageView, et quand je règle l'animation, elle masque l'image, puis la fait apparaître en fondu... Y a-t-il un moyen d'arranger cela ? Je veux dire, quand je fais imageView.setImageBitmap(secondImage) ; l'image ne s'affiche pas immédiatement, mais seulement lorsque l'animation en fondu est exécutée ?

100voto

Crocodile Points 982

Je voulais atteindre le même objectif que vous, j'ai donc écrit la méthode suivante qui fait exactement cela si vous lui passez une ImageView et une liste de références à des images dessinables.

ImageView demoImage = (ImageView) findViewById(R.id.DemoImage);
int imagesToShow[] = { R.drawable.image1, R.drawable.image2,R.drawable.image3 };

animate(demoImage, imagesToShow, 0,false);  

  private void animate(final ImageView imageView, final int images[], final int imageIndex, final boolean forever) {

  //imageView <-- The View which displays the images
  //images[] <-- Holds R references to the images to display
  //imageIndex <-- index of the first image to show in images[] 
  //forever <-- If equals true then after the last image it starts all over again with the first image resulting in an infinite loop. You have been warned.

    int fadeInDuration = 500; // Configure time values here
    int timeBetween = 3000;
    int fadeOutDuration = 1000;

    imageView.setVisibility(View.INVISIBLE);    //Visible or invisible by default - this will apply when the animation ends
    imageView.setImageResource(images[imageIndex]);

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

    Animation fadeOut = new AlphaAnimation(1, 0);
    fadeOut.setInterpolator(new AccelerateInterpolator()); // and this
    fadeOut.setStartOffset(fadeInDuration + timeBetween);
    fadeOut.setDuration(fadeOutDuration);

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

    animation.setAnimationListener(new AnimationListener() {
        public void onAnimationEnd(Animation animation) {
            if (images.length - 1 > imageIndex) {
                animate(imageView, images, imageIndex + 1,forever); //Calls itself until it gets to the end of the array
            }
            else {
                if (forever == true){
                animate(imageView, images, 0,forever);  //Calls itself to start the animation all over again in a loop if forever = true
                }
            }
        }
        public void onAnimationRepeat(Animation animation) {
            // TODO Auto-generated method stub
        }
        public void onAnimationStart(Animation animation) {
            // TODO Auto-generated method stub
        }
    });
}

69voto

Aldryd Points 706

Pour mettre en œuvre cette méthode de la manière dont vous avez commencé, vous devrez ajouter un fichier AnimationListener afin de pouvoir détecter le début et la fin d'une animation. Lorsque onAnimationEnd() pour le fondu en sortie est appelé, vous pouvez définir la visibilité de votre objet ImageView sur View.INVISIBLE, changer les images et commencer votre animation de fondu en entrée - vous aurez besoin d'un autre AnimationListener ici aussi. Lorsque vous recevez la fonction onAnimationEnd() pour votre animation en fondu, réglez l'ImageView sur View.VISIBLE et vous devriez obtenir l'effet que vous recherchez.

J'ai déjà mis en œuvre un effet similaire, mais j'ai utilisé un fichier de type ViewSwitcher avec 2 ImageViews plutôt qu'un seul ImageView. Vous pouvez définir les animations "in" et "out" pour le ViewSwitcher avec votre fade in et fade out afin qu'il puisse gérer l'implémentation de l'AnimationListener. Ensuite, tout ce que vous avez à faire est d'alterner entre les deux ImageViews.

Edit : Pour être un peu plus utile, voici un exemple rapide de l'utilisation du ViewSwitcher. J'ai inclus la source complète à https://github.com/aldryd/imageswitcher .

activité_main.xml

    <ViewSwitcher
        android:id="@+id/switcher"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:inAnimation="@anim/fade_in"
        android:outAnimation="@anim/fade_out" >

        <ImageView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:scaleType="fitCenter"
            android:src="@drawable/sunset" />

        <ImageView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:scaleType="fitCenter"
            android:src="@drawable/clouds" />
    </ViewSwitcher>

MainActivity.java

    // Let the ViewSwitcher do the animation listening for you
    ((ViewSwitcher) findViewById(R.id.switcher)).setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            ViewSwitcher switcher = (ViewSwitcher) v;

            if (switcher.getDisplayedChild() == 0) {
                switcher.showNext();
            } else {
                switcher.showPrevious();
            }
        }
    });

47voto

munkay Points 395

Avez-vous pensé à utiliser TransitionDrawable au lieu d'animations personnalisées ? https://developer.Android.com/reference/Android/graphics/drawable/TransitionDrawable.html

Une façon d'atteindre ce que vous recherchez est :

// create the transition layers
Drawable[] layers = new Drawable[2];
layers[0] = new BitmapDrawable(getResources(), firstBitmap);
layers[1] = new BitmapDrawable(getResources(), secondBitmap);

TransitionDrawable transitionDrawable = new TransitionDrawable(layers);
imageView.setImageDrawable(transitionDrawable);
transitionDrawable.startTransition(FADE_DURATION);

3voto

radhoo Points 1185

Basé sur la solution d'Aladin Q, voici une fonction d'aide que j'ai écrite, qui changera l'image dans une imageview tout en exécutant une petite animation en fondu enchaîné :

public static void ImageViewAnimatedChange(Context c, final ImageView v, final Bitmap new_image) {
        final Animation anim_out = AnimationUtils.loadAnimation(c, android.R.anim.fade_out); 
        final Animation anim_in  = AnimationUtils.loadAnimation(c, android.R.anim.fade_in); 
        anim_out.setAnimationListener(new AnimationListener()
        {
            @Override public void onAnimationStart(Animation animation) {}
            @Override public void onAnimationRepeat(Animation animation) {}
            @Override public void onAnimationEnd(Animation animation)
            {
                v.setImageBitmap(new_image); 
                anim_in.setAnimationListener(new AnimationListener() {
                    @Override public void onAnimationStart(Animation animation) {}
                    @Override public void onAnimationRepeat(Animation animation) {}
                    @Override public void onAnimationEnd(Animation animation) {}
                });
                v.startAnimation(anim_in);
            }
        });
        v.startAnimation(anim_out);
    }

1voto

Aladin Q Points 169

J'utilise ce genre de routine pour enchaîner les animations de manière programmée.

    final Animation anim_out = AnimationUtils.loadAnimation(context, android.R.anim.fade_out); 
    final Animation anim_in  = AnimationUtils.loadAnimation(context, android.R.anim.fade_in); 

    anim_out.setAnimationListener(new AnimationListener()
    {
        @Override
        public void onAnimationStart(Animation animation) {}

        @Override
        public void onAnimationRepeat(Animation animation) {}

        @Override
        public void onAnimationEnd(Animation animation)
        {
            ////////////////////////////////////////
            // HERE YOU CHANGE YOUR IMAGE CONTENT //
            ////////////////////////////////////////
            //ui_image.setImage...

            anim_in.setAnimationListener(new AnimationListener()
            {
                @Override
                public void onAnimationStart(Animation animation) {}

                @Override
                public void onAnimationRepeat(Animation animation) {}

                @Override
                public void onAnimationEnd(Animation animation) {}
            });

            ui_image.startAnimation(anim_in);
        }
    });

    ui_image.startAnimation(anim_out);

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X