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 ImageViews

แก้ไข: เพื่อให้มีประโยชน์มากขึ้นนี่คือตัวอย่างสั้น ๆ ของวิธีการใช้ 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 แยก)?
รอน

@ รอนฉันไม่ได้เปรียบเทียบประสิทธิภาพของวิธีการต่างๆ เมื่อเทียบกับการถอดรหัส / การทำงานกับบิตแมปสำหรับออบเจ็กต์ ImageView ฉันคิดว่าการใช้ ViewSwitcher กับการใช้ AnimationListener ด้วยตัวคุณเองจะไม่สามารถสังเกตเห็นได้ชัดเจน เมื่อเร็ว ๆ นี้ฉันพบว่าหากคุณใช้ API 11 ขึ้นไปคุณสามารถใช้คลาส Animation ใหม่ ๆ ได้ คุณสามารถดูตัวอย่างการแสดงผลแบบ crossfading 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% นับในเมธอด onAnimationRepeat ของคุณได้
butelo

2
@ จระเข้คุณคิดว่าอาจมีปัญหาหน่วยความจำในรหัสของคุณ ปล่อยให้กิจกรรมที่มีรหัสด้านบนทำงานต่อไป มันจะสร้างวัตถุ AnimationSet มากมาย มีความเป็นไปได้หรือไม่ที่จะเกิดข้อผิดพลาดกับ outOfMemory หลังจากเวลาผ่านไปสักครู่?
อัญมณี

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

ขออภัยสำหรับการกระแทก แต่ถ้าฉันใช้สิ่งนี้ใน Handler และมีการวนซ้ำแบบถาวรแอปจะสูญเสียประสิทธิภาพในภาพเคลื่อนไหวอื่น ๆ ที่จางลง / จางหายไป คำแนะนำใด ๆ ?
เจมส์

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/…เพื่อทำความสะอาดโค้ด
zyamys

ขอขอบคุณ!! ยังคงเกี่ยวข้อง ... สิ่งที่ฉันต้องการมากที่สุดในตอนนี้!
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
}

}

ฉันหวังว่านี่จะช่วยได้อย่างแน่นอน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.