Android 通过 ImageView 淡入淡出

我制作的幻灯片出了点问题。

我已经在 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>

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 中,当我设置动画时,它隐藏了图像,淡入... 有没有办法解决这个问题,我的意思是,当我执行 SetImageBitmap (第二幅图像) ;命令时,图像不会立即显示,只有当淡入动画执行时才会显示?

154276 次浏览

To implement this the way you have started, you'll need to add an AnimationListener so that you can detect the beginning and ending of an animation. When onAnimationEnd() for the fade out is called, you can set the visibility of your ImageView object to View.INVISIBLE, switch the images and start your fade in animation - you'll need another AnimationListener here too. When you receive onAnimationEnd() for your fade in animation, set the ImageView to be View.VISIBLE and that should give you the effect you're looking for.

I've implemented a similar effect before, but I used a ViewSwitcher with 2 ImageViews rather than a single ImageView. You can set the "in" and "out" animations for the ViewSwitcher with your fade in and fade out so it can manage the AnimationListener implementation. Then all you need to do is alternate between the 2 ImageViews.

Edit: To be a bit more useful, here is a quick example of how to use the ViewSwitcher. I have included the full source at 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();
}
}
});

I wanted to achieve the same goal as you, so I wrote the following method which does exactly that if you pass it an ImageView and a list of references to image drawables.

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

I'm using this kind of routine for programmatically chaining animations.

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

Based on Aladin Q's solution, here is a helper function that I wrote, that will change the image in an imageview while running a little fade out / fade in 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);
}

Have you thought of using TransitionDrawable instead of custom animations? https://developer.android.com/reference/android/graphics/drawable/TransitionDrawable.html

One way to achieve what you are looking for is:

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

I used used fadeIn animation to replace new image for old one

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

The best and the easiest way, for me was this..

->Simply create a thread with Handler containing 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();
}

you can do it by two simple point and change in your code

1.In your xml in anim folder of your project, Set the fade in and fade out duration time not equal

2.In you java class before the start of fade out animation, set second imageView visibility Gone then after fade out animation started set second imageView visibility which you want to fade in 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" />

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

This is probably the best solution you'll get. Simple and Easy. I learned it on udemy. Suppose you have two images having image id's id1 and id2 respectively and currently the image view is set as id1 and you want to change it to the other image everytime someone clicks in. So this is the basic code in MainActivity.java File

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
}


}

I hope this will surely help

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