Android se desvanece y se desvanece con ImageView


89

Tengo algunos problemas con una presentación de diapositivas que estoy creando.

He creado 2 animaciones en xml para fade in y 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>

Lo que estoy intentando hacer es cambiar las imágenes de un ImageView usando el efecto de desvanecimiento, por lo que la imagen que se muestra actualmente se desvanecerá y otra se desvanecerá. Teniendo en cuenta que ya tengo una imagen configurada, puedo desvanecer esta imagen sin problema, con esto:

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

Pero luego, configuro la siguiente imagen para que se muestre:

    imageView.setImageBitmap(secondImage);

Simplemente aparece en imageView, y cuando configuro la animación, oculta la imagen, la atenúa ... ¿Hay alguna forma de arreglar eso, quiero decir, cuando hago imageView.setImageBitmap (secondImage); comando, la imagen no aparece inmediatamente, y solo cuando se ejecuta el fundido en la animación?

Respuestas:


66

Para implementar esto de la forma en que comenzó, deberá agregar un AnimationListener para que pueda detectar el comienzo y el final de una animación. Cuando se llama a onAnimationEnd () para el desvanecimiento, puede establecer la visibilidad de su objeto ImageView en View.INVISIBLE, cambiar las imágenes y comenzar su desvanecimiento en la animación; aquí también necesitará otro AnimationListener. Cuando reciba onAnimationEnd () para su fundido en la animación, configure ImageView en View.VISIBLE y eso debería darle el efecto que está buscando.

Implementé un efecto similar antes, pero usé un ViewSwitcher con 2 ImageViews en lugar de un solo ImageView. Puede configurar las animaciones de "entrada" y "salida" para ViewSwitcher con su fundido de entrada y salida para que pueda gestionar la implementación de AnimationListener. Entonces todo lo que necesita hacer es alternar entre los 2 ImageViews.

Editar: Para ser un poco más útil, aquí hay un ejemplo rápido de cómo usar ViewSwitcher. He incluido la fuente completa en 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();
            }
        }
    });

¡Gracias hombre! ¡Me olvidé del serVisible! Y gracias por el consejo de ViewSwitcher, parece más fácil que manejar todo yo solo.
IPValverde

@Aldryd ¿Es esto más eficiente en términos de rendimiento? ¿En comparación con la respuesta seleccionada (archivo XML separado)?
Ron

@Ron Realmente no comparé el rendimiento de los diferentes métodos. En comparación con la decodificación / trabajo con mapas de bits para los objetos ImageView, creo que usar un ViewSwitcher versus implementar el AnimationListener usted mismo no sería muy notable. Recientemente descubrí que si está usando API 11 o superior, puede usar algunas clases de animación nuevas. Puede ver un ejemplo de crossfading 2 vistas con API 11 aquí: developer.android.com/training/animation/crossfade.html
Aldryd

96

Quería lograr el mismo objetivo que usted, así que escribí el siguiente método que hace exactamente eso si le pasa un ImageView y una lista de referencias a elementos de diseño de imágenes.

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
Para mostrar cómo las animaciones de aparición y desaparición gradual se pueden definir en el código, señor, obtenga mi voto
Herr Grumps

También puede contar repeticiones y hacer un recuento de Array.lenght% en su método onAnimationRepeat
butelo

2
@Crocodile ¿Crees que podría haber un problema de memoria en tu código? Deje que la actividad con el código anterior siga ejecutándose. Creará tantos objetos AnimationSet. ¿Existe alguna posibilidad de que se bloquee sin outOfMemory después de algún tiempo?
Gema

1
¡Usted señor es un salvavidas!
faizanjehangir

2
@Gem: ¿por qué esa asignación en particular causaría un problema? Cada vez que se llama a imageView.setAnimation (animación), se pierde cualquier referencia a una animación anterior, por lo que el recolector de basura podría eliminar este objeto anterior. AFAIK, no es un problema de memoria.
greg7gkb

46

¿Ha pensado en utilizar TransitionDrawable en lugar de animaciones personalizadas? https://developer.android.com/reference/android/graphics/drawable/TransitionDrawable.html

Una forma de lograr lo que busca es:

// 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
Esta es la mejor respuesta para esta pregunta.
DragonT

Perdón por los golpes, pero si uso esto en un controlador y lo tengo en un bucle permanente, la aplicación pierde rendimiento en otra animación constante de aparición / desaparición gradual que tengo. ¿Alguna recomendación?
James

TransitionDrawable solo puede manejar dos imágenes / capa.
Signcodeindie

El elemento de diseño de transición provoca la excepción AppNotIdleException al ejecutar la prueba de espresso
PK Gupta

6

Usé la animación fadeIn para reemplazar la nueva imagen por la anterior

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

2
Consulte android-developers.blogspot.com/2011/05/… para obtener un código más limpio.
zyamys

¡¡GRACIAS!! sigue siendo relevante ... ¡Lo que más necesitaba ahora!
Teekam Suthar

1
¡¡Gracias!! Esta es la mejor respuesta ... muy simple de implementar y funciona sin problemas.
user3152377

3

Basado en la solución de Aladin Q, aquí hay una función auxiliar que escribí, que cambiará la imagen en una vista de imagen mientras ejecuta un pequeño desvanecimiento / desvanecimiento en la animació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);
    }

3

puedes hacerlo con dos simples puntos y cambiar tu código

1.En su xml en la carpeta anim de su proyecto, establezca el tiempo de duración de fade in y fade out no igual

2.En su clase java antes del inicio de la animación de desvanecimiento, configure la segunda visibilidad de la vista de imagen Desaparecido y luego, después de que la animación de desvanecimiento comience, configure la segunda visibilidad de la vista de imagen que desea que se desvanezca en visible

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 tu clase de 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

Para un fundido infinito de entrada y salida

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

Estoy usando este tipo de rutina para encadenar animaciones mediante programación.

    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

La mejor y más fácil forma para mí fue esta ...

-> Simplemente cree un hilo con Handler que contenga 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

Esta es probablemente la mejor solución que obtendrá. Simple y fácil. Lo aprendí en udemy. Suponga que tiene dos imágenes con id1 e id2 de imagen respectivamente y que actualmente la vista de la imagen está configurada como id1 y desea cambiarla a la otra imagen cada vez que alguien hace clic. Así que este es el código básico en 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
}

}

Espero que esto sin duda ayude

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.