Android зникає і згасає за допомогою ImageView


89

У мене є деякі проблеми зі слайд-шоу, яке я будую.

Я створив 2 анімації в xml для зникання та зникання:

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>

Що я не намагаюся зробити, це змінити зображення з ImageView за допомогою ефекту вицвітання, так що відображуване в даний час зображення зникає, а інше зникає. Враховуючи, що у мене вже встановлено зображення, я можу зникнути це зображення без проблема, з цим:

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

Але потім я встановив для відображення наступне зображення:

    imageView.setImageBitmap(secondImage);

Він просто відображається в imageView, і коли я встановлюю анімацію, зображення приховується, зникає ... Чи є спосіб це виправити, я маю на увазі, коли я роблю imageView.setImageBitmap (secondImage); команда не відображається одразу, і лише коли виконується затухання в анімації?

Відповіді:


66

Щоб реалізувати це так, як ви розпочали, вам потрібно додати AnimationListener, щоб ви могли виявити початок і кінець анімації. Коли викликається onAnimationEnd () для вицвітання, ви можете встановити видимість вашого об’єкта ImageView на View.INVISIBLE, переключити зображення та розпочати ваш затухання в анімації - вам також знадобиться інший AnimationListener тут. Коли ви отримуєте onAnimationEnd () для вашого зникнення в анімації, встановіть ImageView на View.VISIBLE, і це має дати вам ефект, який ви шукаєте.

Я застосовував подібний ефект раніше, але я використовував ViewSwitcher з 2 ImageViews, а не одним ImageView. Ви можете встановити анімацію "вхід" і "вихід" для ViewSwitcher, використовуючи вбудовування і згасання, щоб він міг керувати реалізацією AnimationListener. Тоді все, що вам потрібно зробити, це чергувати 2 ImageView.

Редагувати: Щоб бути трохи кориснішим, ось короткий приклад використання ViewSwitcher. Я включив повне джерело на 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();
            }
        }
    });

Дякую людино! Я забув про serVisible! І дякую за підказку ViewSwitcher, здається, це простіше, ніж впоратися з усім самостійно.
IPValverde

@Aldryd Це ефективніше з точки зору продуктивності? Порівняно з обраною відповіддю (окремий файл XML)?
Рон

@Ron Я не дуже порівнював ефективність різних методів. Порівняно з декодуванням / роботою з растровими зображеннями для об’єктів ImageView, я вважаю, що використання ViewSwitcher проти реалізації AnimationListener самостійно було б не дуже помітним. Нещодавно я дізнався, що якщо ви використовуєте API 11 або вище, ви можете використовувати деякі нові класи анімації. Ви можете побачити приклад перехресного перегляду 2 переглядів з API 11 тут: developer.android.com/training/animation/crossfade.html
Aldryd

96

Я хотів досягти тієї ж мети, що і ви, тому я написав наступний метод, який робить саме це, якщо ви передаєте йому ImageView та список посилань на малюнки, що малюються.

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
За те, щоб показати, як можна визначити в коді анімацію затухання та зменшення, ви, сер, отримайте мій голос
Herr Grumps

Ви також можете порахувати повторення та зробити Array.lenght% count у вашому методі
onAnimationRepeat

2
@Crocodile Чи вважаєте ви, що у вашому коді може бути проблема з пам'яттю. Нехай діяльність із зазначеним вище кодом продовжується. Це створить стільки об’єктів AnimationSet. Чи існує якась можливість того, що він через деякий час вийде із системи outOfMemory?
Gem

1
Ви, сер, рятівник!
faizanjehangir

2
@Gem - чому саме цей розподіл може спричинити проблему? Кожного разу, коли imageView.setAnimation (анімація) викликається, будь-яке посилання на попередню анімацію втрачається, тому збирач сміття зможе видалити цей попередній об’єкт. AFAIK, не проблема пам'яті.
greg7gkb

46

Ви думали використовувати TransitionDrawable замість спеціальних анімацій? https://developer.android.com/reference/android/graphics/drawable/TransitionDrawable.html

Одним із способів досягти того, що ви шукаєте, є:

// 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
Це найкраща відповідь на це питання.
DragonT

Вибачте за зіткнення, але якщо я використовую це в обробнику і маю його в постійному циклі, програма втрачає продуктивність в іншій постійній анімації, що зникає / згасає. Будь-які рекомендації?
Джеймс

TransitionDrawable може обробляти лише два зображення / шар.
Signcodeindie

Перехідний малюнок викликає AppNotIdleException під час запуску тесту еспресо
PK Gupta

6

Я використав анімацію fadeIn для заміни нового зображення на старе

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

2
Дивіться android-developers.blogspot.com/2011/05/…, щоб дізнатися про чистіший код.
зямис

ДЯКУЮ!! все ще актуальне ... Те, що мені найбільше потрібно було зараз!
Teekam Suthar

1
Дякую!! Це найкраща відповідь ... дуже проста у реалізації та працює безперебійно.
user3152377

3

На основі рішення Aladin Q, ось допоміжна функція, про яку я писав, яка змінить зображення в режимі перегляду зображень під час запуску трохи затухання / затухання в анімації:

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

Ви можете зробити це двома простими точками і змінити свій код

1. У вашому xml в папці anim вашого проекту встановіть не однаковий час тривалості зникання та згасання

2.У вашому класі Java перед початком зникаючої анімації встановіть другу видимість imageView Зник, а після запущеної анімації встановіть другу видимість imageView, яку ви хочете зникнути

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

У вас клас 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

Для нескінченного Fade In and Out

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

Я використовую цю процедуру для програмно прив’язаних анімацій.

    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

Найкращим і найпростішим способом для мене був такий ..

-> Просто створіть нитку за допомогою Handler, що містить 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

Це, мабуть, найкраще рішення, яке ви отримаєте. Простий і легкий. Я дізнався про це на udemy. Припустимо, у вас є два зображення, які мають ідентифікатори зображень id1 та id2 відповідно, і наразі перегляд зображення встановлений як id1, і ви хочете змінити його на інше зображення кожного разу, коли хтось натискає. Отже, це основний код у MainActivity.javaфайлі

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
}

}

Я сподіваюся, це напевно допоможе

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.