Android dissolvenza in entrata e in uscita con ImageView


89

Ho dei problemi con una presentazione che sto creando.

Ho creato 2 animazioni in xml per fade in e fade out:

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>

Quello che sto provando a fare è cambiare le immagini da un ImageView usando l'effetto di dissolvenza, quindi l'immagine attualmente visualizzata si dissolverà e un'altra si dissolverà in apertura. Considerando che ho un'immagine già impostata, posso dissolvere questa immagine senza problema, con questo:

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

Ma poi, ho impostato l'immagine successiva da visualizzare:

    imageView.setImageBitmap(secondImage);

Viene visualizzato solo in imageView, e quando imposto l'animazione nasconde l'immagine, la dissolvenza in entrata ... C'è un modo per risolverlo, voglio dire, quando faccio imageView.setImageBitmap (secondImage); il comando, l'immagine non compare immediatamente e solo quando viene eseguita l'animazione in dissolvenza?

Risposte:


66

Per implementarlo nel modo in cui hai iniziato, dovrai aggiungere un AnimationListener in modo da poter rilevare l'inizio e la fine di un'animazione. Quando viene chiamato onAnimationEnd () per la dissolvenza in chiusura, puoi impostare la visibilità del tuo oggetto ImageView su View.INVISIBLE, cambiare le immagini e avviare la tua animazione in dissolvenza - anche qui avrai bisogno di un altro AnimationListener. Quando ricevi onAnimationEnd () per la tua animazione in dissolvenza, imposta ImageView su View.VISIBLE e questo dovrebbe darti l'effetto che stai cercando.

Ho implementato un effetto simile in precedenza, ma ho usato un ViewSwitcher con 2 ImageView invece di un singolo ImageView. Puoi impostare le animazioni "in" e "out" per ViewSwitcher con il tuo fade in e fade out in modo che possa gestire l'implementazione di AnimationListener. Quindi tutto ciò che devi fare è alternare tra le 2 ImageView.

Modifica: per essere un po 'più utile, ecco un rapido esempio di come utilizzare ViewSwitcher. Ho incluso la fonte completa su 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();
            }
        }
    });

Grazie uomo! Mi sono dimenticato di serVisible! E grazie per il suggerimento di ViewSwitcher, sembra più facile che gestire tutto da solo.
IPValverde

@ Aldryd È più efficiente dal punto di vista delle prestazioni? Rispetto alla risposta selezionata (file XML separato)?
Ron

@ Ron non ho davvero confrontato le prestazioni dei diversi metodi. Rispetto alla decodifica / al lavoro con le bitmap per gli oggetti ImageView, penserei che l'utilizzo di un ViewSwitcher rispetto all'implementazione di AnimationListener da soli non sarebbe molto evidente. Recentemente ho scoperto che se stai usando API 11 o superiore, puoi usare alcune nuove classi di animazione. Puoi vedere un esempio di dissolvenza incrociata di 2 visualizzazioni con API 11 qui: developer.android.com/training/animation/crossfade.html
Aldryd

96

Volevo raggiungere il tuo stesso obiettivo, quindi ho scritto il seguente metodo che fa esattamente questo se gli passi un ImageView e un elenco di riferimenti a immagini disegnabili.

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

1
Per mostrare come le animazioni di dissolvenza in
entrata

Puoi anche contare le ripetizioni e fare un conteggio Array.lenght% nel tuo metodo
onAnimationRepeat

2
@Crocodile Pensi che ci possa essere un problema di memoria nel tuo codice. Lascia che l'attività con il codice precedente continui a funzionare. Creerà così tanti oggetti AnimationSet. C'è qualche possibilità che si blocchi con outOfMemory dopo un po 'di tempo?
Gem

1
Siete un vero toccasana!
faizanjehangir

2
@Gem - perché quella particolare allocazione potrebbe causare un problema? Ogni volta che viene chiamato imageView.setAnimation (animation) qualsiasi riferimento a un'animazione precedente viene perso, quindi il garbage collector sarà in grado di eliminare questo oggetto precedente. AFAIK, non è un problema di memoria.
greg7gkb

46

Hai pensato di utilizzare TransitionDrawable al posto delle animazioni personalizzate? https://developer.android.com/reference/android/graphics/drawable/TransitionDrawable.html

Un modo per ottenere ciò che stai cercando è:

// 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);

2
Questa è la migliore risposta a questa domanda.
DragonT

Ci scusiamo per il bumping, ma se lo uso in un Handler e lo ho in un ciclo permanente, l'app perde le prestazioni in un'altra animazione di dissolvenza in entrata / uscita costante che ho. Qualche consiglio?
James,

TransitionDrawable può gestire solo due immagini / livello.
Signcodeindie

Il drawable di transizione causa AppNotIdleException durante l'esecuzione del test espresso
PK Gupta

6

Ho usato l'animazione fadeIn per sostituire la nuova immagine con quella vecchia

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

2
Vedere android-developers.blogspot.com/2011/05/… per un codice più pulito.
zyamys

GRAZIE!! ancora rilevante ... Quello di cui avevo più bisogno in questo momento!
Teekam Suthar

1
Grazie!! Questa è la risposta migliore ... molto semplice da implementare e funziona senza problemi.
user3152377

3

Sulla base della soluzione di Aladin Q, ecco una funzione di supporto che ho scritto, che cambierà l'immagine in una visualizzazione immagine durante l'esecuzione di una piccola animazione in dissolvenza / dissolvenza in apertura:

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

puoi farlo con due semplici punti e cambiare il tuo codice

1.Nel tuo xml nella cartella anim del tuo progetto, imposta la durata della dissolvenza in entrata e in uscita non uguale

2.Nella tua classe java prima dell'inizio dell'animazione di dissolvenza, imposta la seconda immagine Visibilità della vista Andato poi dopo l'inizio dell'animazione di dissolvenza imposta la seconda immagine Visibilità della vista che vuoi rendere visibile in dissolvenza

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" />

Nella tua classe Java

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);

3

Per infinite dissolvenze in entrata e in uscita

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

Sto usando questo tipo di routine per concatenare le animazioni a livello di codice.

    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

Il modo migliore e più semplice, per me era questo ..

-> Crea semplicemente un thread con Handler contenente 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

Questa è probabilmente la migliore soluzione che otterrai. Semplice e facile. L'ho imparato su udemy. Supponi di avere due immagini con ID immagine rispettivamente id1 e id2 e attualmente la visualizzazione dell'immagine è impostata come id1 e vuoi cambiarla nell'altra immagine ogni volta che qualcuno fa clic. Quindi questo è il codice di base in MainActivity.javaFile

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
}

}

Spero che questo possa sicuramente aiutare

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.