web-dev-qa-db-fra.com

Android estompage en fondu à l'aide de ImageView

J'ai des problèmes avec un diaporama que je construis.

J'ai créé 2 animations au format xml pour les fondus en entrée et en sortie:

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 je veux faire, c’est changer les images d’un ImageView en utilisant l’effet de fondu. Ainsi, l’image affichée disparaîtra et une autre s’apparaîtra. Étant donné 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);

Il apparaît dans l'imageView, et lorsque je règle l'animation, il masque l'image, le fondu enchaîné ... Y a-t-il un moyen de remédier à cela, je veux dire, quand je fais imageView .setImageBitmap (secondImage); , l’image ne s’affiche pas immédiatement, et seulement lorsque l’animation de fondu est exécutée?

84
IPValverde

Pour mettre cela en œuvre de la manière dont vous avez commencé, vous devez ajouter un AnimationListener afin de pouvoir détecter le début et la fin d'une animation. Lorsque onAnimationEnd () pour le fondu de sortie est appelé, vous pouvez définir la visibilité de votre objet ImageView sur View.INVISIBLE, changer les images et démarrer votre animation de fondu en fondu - vous aurez également besoin d'un autre AnimationListener. Lorsque vous recevez onAnimationEnd () pour votre animation en fondu, définissez ImageView sur View.VISIBLE, ce qui devrait vous donner l'effet recherché.

J'ai déjà implémenté un effet similaire auparavant, mais j'ai utilisé un ViewSwitcher avec 2 ImageViews plutôt qu'un seul ImageView. Vous pouvez définir les animations "in" et "out" pour le ViewSwitcher avec vos fondus en entrée et fondus en sortie afin qu'il puisse gérer l'implémentation AnimationListener. Ensuite, tout ce que vous avez à faire est d’alterner entre les 2 ImageViews.

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

activity_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();
            }
        }
    });
64
Aldryd

Je souhaitais atteindre le même objectif que vous. J'ai donc écrit la méthode suivante, qui fonctionne exactement si vous lui transmettez 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){
                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
        }
    });
}
96
Crocodile

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

Une façon de réaliser 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);
42
munkay

J'ai utilisé l'animation fadeIn utilisée pour remplacer la nouvelle image par l'ancienne

ObjectAnimator.ofFloat(imageView, View.ALPHA, 0.2f, 1.0f).setDuration(1000).start();
4
Rafael

Sur la base de la solution d’Aladin Q, voici une fonction d’aide que j’ai écrite, qui modifiera l’image dans une image au cours de l’exécution d’un petit fondu en animation:

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);
    }
3
radhoo

Le meilleur et le plus simple, pour moi était ça ..

-> Créez simplement un thread avec Handler contenant sleep ().

private ImageView myImageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_shape_count); myImageView= (ImageView)findViewById(R.id.shape1);
    Animation myFadeInAnimation = AnimationUtils.loadAnimation(this, R.anim.fadein);
    myImageView.startAnimation(myFadeInAnimation);

    new Thread(new Runnable() {
        private Handler handler = new Handler(){
            @Override
            public void handleMessage(Message msg) {
                Log.w("hendler", "recived");
                    Animation myFadeOutAnimation = AnimationUtils.loadAnimation(getBaseContext(), R.anim.fadeout);
                    myImageView.startAnimation(myFadeOutAnimation);
                    myImageView.setVisibility(View.INVISIBLE);
            }
        };

        @Override
        public void run() {
            try{
                Thread.sleep(2000); // your fadein duration
            }catch (Exception e){
            }
            handler.sendEmptyMessage(1);

        }
    }).start();
}
1
Sankar Behera

vous pouvez le faire en deux points simples et changer dans votre code

1.Dans votre dossier xml dans le dossier d’animation de votre projet, définissez des durées de fade in et fade out différentes.

2.Dans Java avant le début de l'animation en fondu, définissez la visibilité de la seconde imageView. Fini, après l'animation en fondu, définissez la visibilité de la seconde imageView que vous souhaitez afficher en fondu.

fadeout.xml

<alpha
    Android:duration="4000"
    Android:fromAlpha="1.0"
    Android:interpolator="@Android:anim/accelerate_interpolator"
    Android:toAlpha="0.0" />

fadein.xml

<alpha
    Android:duration="6000"
    Android:fromAlpha="0.0"
    Android:interpolator="@Android:anim/accelerate_interpolator"
    Android:toAlpha="1.0" />

En vous Java class

Animation animFadeOut = AnimationUtils.loadAnimation(this, R.anim.fade_out);
    ImageView iv = (ImageView) findViewById(R.id.imageView1);
    ImageView iv2 = (ImageView) findViewById(R.id.imageView2);
    iv.setVisibility(View.VISIBLE);
    iv2.setVisibility(View.GONE);
    animFadeOut.reset();
    iv.clearAnimation();
    iv.startAnimation(animFadeOut);

    Animation animFadeIn = AnimationUtils.loadAnimation(this, R.anim.fade_in);
    iv2.setVisibility(View.VISIBLE);
    animFadeIn.reset();
    iv2.clearAnimation();
    iv2.startAnimation(animFadeIn);
1
Hadi Samadbin

J'utilise ce genre de routine pour chaîner des animations par programme.

    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);
1
Aladin Q

C'est probablement la meilleure solution que vous obtiendrez. Simple et facile. Je l'ai appris sur Udemy. Supposons que vous avez deux images portant respectivement id1 et id2, et que la vue d'image est définie sur id1 et que vous souhaitez la remplacer par une autre image chaque fois que quelqu'un clique dessus. Il s'agit donc du code de base dans MainActivity.Java Fichier

int clickNum=0;
public void click(View view){
clickNum++;
ImageView a=(ImageView)findViewById(R.id.id1);
ImageView b=(ImageView)findViewById(R.id.id2);
if(clickNum%2==1){
  a.animate().alpha(0f).setDuration(2000); //alpha controls the transpiracy
}
else if(clickNum%2==0){
  b.animate().alpha(0f).setDuration(2000); //alpha controls the transpiracy
}

}

J'espère que cela aidera sûrement

1
Saurabh Kumar

Pour un fondu à l'infini

AlphaAnimation fadeIn=new AlphaAnimation(0,1);

AlphaAnimation fadeOut=new AlphaAnimation(1,0);


final AnimationSet set = new AnimationSet(false);

set.addAnimation(fadeIn);
set.addAnimation(fadeOut);
fadeOut.setStartOffset(2000);
set.setDuration(2000);
imageView.startAnimation(set);

set.setAnimationListener(new Animation.AnimationListener() {
    @Override
    public void onAnimationStart(Animation animation) { }
    @Override
    public void onAnimationRepeat(Animation animation) { }
    @Override
    public void onAnimationEnd(Animation animation) {
        imageView.startAnimation(set);
    }
});
1
Aryan Sharma