Creating animation on ImageView while changing image resource - android

I have only one ImageView in my layout and I am changing its resource when a gasture event detected. I just want to show an animation while changing resource of ImageView. Can I use ViewFlipper with one ImageView?

For a single imageview you can use this helper function:
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);
}

Here's an example using ImageSwitcher like #Konstantin Burov suggested:
Add this ImageSwitcher element to your xml layout:
<ImageSwitcher
android:id="#+id/slide_trans_imageswitcher"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</ImageSwitcher>
Create in and out animations in res/anim/:
Out animation:
//left_to_right_out.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
<translate android:fromXDelta="0%" android:toXDelta="100%"
android:fromYDelta="0%" android:toYDelta="0%"
android:duration="700"/>
</set>
And in animation:
//left_to_right_in.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
<translate android:fromXDelta="-100%" android:toXDelta="0%"
android:fromYDelta="0%" android:toYDelta="0%"
android:duration="700"/>
</set>
Initialize them in your code:
Animation in = AnimationUtils.loadAnimation(this, R.anim.left_to_right_in);
Animation out = AnimationUtils.loadAnimation(this, R.anim.left_to_right_out);
Initialize your ImageSwitcher:
private ImageSwitcher imageSwitcher;
imageSwitcher = (ImageSwitcher)findViewById(R.id.slide_trans_imageswitcher);
Attach the animations to it:
imageSwitcher.setInAnimation(in);
imageSwitcher.setOutAnimation(out);
Now everytime you set an image resource for imageSwitcher, it will switch in a slide animation.
For example we can change the image every X seconds:
private int animationCounter = 1;
private Handler imageSwitcherHandler;
imageSwitcherHandler = new Handler(Looper.getMainLooper());
imageSwitcherHandler.post(new Runnable() {
#Override
public void run() {
switch (animationCounter++) {
case 1:
imageSwitcher.setImageResource(R.drawable.image1);
break;
case 2:
imageSwitcher.setImageResource(R.drawable.image2);
break;
case 3:
imageSwitcher.setImageResource(R.drawable.image3);
break;
}
animationCounter %= 4;
if(animationCounter == 0 ) animationCounter = 1;
imageSwitcherHandler.postDelayed(this, 3000);
}
});

I found another way to animate it using transition drawable(I took idea from here)
public static void setImageDrawableWithAnimation(ImageView imageView,
Drawable drawable,
int duration) {
Drawable currentDrawable = imageView.getDrawable();
if (currentDrawable == null) {
imageView.setImageDrawable(drawable);
return;
}
TransitionDrawable transitionDrawable = new TransitionDrawable(new Drawable[] {
currentDrawable,
drawable
});
imageView.setImageDrawable(transitionDrawable);
transitionDrawable.startTransition(duration);
}
Analogous kotlin extension function:
fun ImageView.setImageDrawableWithAnimation(drawable: Drawable, duration: Int = 300) {
val currentDrawable = getDrawable()
if (currentDrawable == null) {
setImageDrawable(drawable)
return
}
val transitionDrawable = TransitionDrawable(arrayOf(
currentDrawable,
drawable
))
setImageDrawable(transitionDrawable)
transitionDrawable.startTransition(duration)
}
If your drawables contains transparent parts, this flag could be useful to prevent old drawable visibility:
transitionDrawable.setCrossFadeEnabled(true);

Consider using Rotate3dAnimation available in the API demo app.
View > Animation > 3D transition
You can also check this question on SO

Related

Layout children frozen after animation

I am animating a ConstraintLayout off screen, then back into screen. However, after animating the ConstraintLayout back into view the child elements (EditTexts and Button) are frozen.
I believe it is because the layout is just showing an image of itself, with the actual elements behind. How can I get the layout to 'redraw'?
Here is an example of the issue:
Here is my code:
slide_out_left.xml:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false" >
<translate android:duration="200" android:fromXDelta="0%" android:toXDelta="-100%"/>
</set>
slide_in_left.xml:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false" >
<translate android:duration="200" android:fromXDelta="-100%" android:toXDelta="0%"/>
</set>
View code:
public void slideCreateFormOutToLeft() {
Animation slideOutLeft = AnimationUtils.loadAnimation(getActivityContext(), R.anim.slide_out_left);
slideOutLeft.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
createTaskViewFormContainer.setVisibility(View.INVISIBLE);
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
createTaskViewFormContainer.startAnimation(slideOutLeft);
}
public void slideCreateFormInFromLeft() {
createTaskViewFormContainer.setVisibility(View.VISIBLE);
Animation slideInLeft = AnimationUtils.loadAnimation(getActivityContext(), R.anim.slide_in_left);
slideInLeft.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
createTaskViewFormContainer.startAnimation(slideInLeft);
}
From this Android documentation
Another disadvantage of the view animation system is that it only
modified where the View was drawn, and not the actual View itself. For
instance, if you animated a button to move across the screen, the
button draws correctly, but the actual location where you can click
the button does not change, so you have to implement your own logic to
handle this.
So the Buttons and EditTexts inside the createTaskViewFormContainer is not in the vicinity of your click area. This is a problem with ViewAnimation and it is recommended to use PropertyAnimation instead, like this:
DisplayMetrics displayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
int screenWidth = displayMetrics.widthPixels;
createTaskViewFormContainer.animate().translationX(-screenWidth).start();
To bring the view back:
createTaskViewFormContainer.animate().translationX(0).start();

How to run two different animations on recyclerView consecutively?

I have a horizontal recyclerView, I want to animate it (by sliding right and then left) when the activity is first opened.
So I do this in onCreate:
final Animation slideRight = AnimationUtils.loadAnimation(this, R.anim.slide_right);
slideRight.setDuration(200);
final Animation slideLeft = AnimationUtils.loadAnimation(this, R.anim.slide_left);
slideLeft.setDuration(200);
RecyclerView recyclerView = findViewById(R.id.recycler_view);
recyclerView.startAnimation(slideRight);
recyclerView.startAnimation(slideLeft);
but seems like only the right slide works
here are my anims:
left slide
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false" >
<translate
android:duration="200"
android:fromXDelta="-100%"
android:fromYDelta="0%"
android:toXDelta="0%"
android:toYDelta="0%" />
</set>
right slide
<translate
android:duration="200"
android:fromXDelta="100%"
android:fromYDelta="0%"
android:toXDelta="0%"
android:toYDelta="0%" />
what am I doing wrong?
EDIT: how is this related to proposed duplicate?
try this one
Animation slideRight = AnimationUtils.loadAnimation(this, R.anim.slide_right);
Animation slideLeft = AnimationUtils.loadAnimation(this, R.anim.slide_left);
slideRight.setDuration(200);
slideLeft.setDuration(200);
slideRight .setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
recyclerView.startAnimation(slideLeft);
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
recyclerView.startAnimation(slideRight);
In this case slideLeft animation will work.. because before the slideRight is working the slideleft is getting started.. so do like this...
slideRight.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
recyclerView.startAnimation(slideLeft);
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
}
At the end of animation right start the animation left
Edit
Or you can start only one anim by adding repeatMode = reverse and repeatCount = 1` in your anim..
android:repeatMode="reverse" android:repeatCount="1"

Fadein Only the Button Text in Android

I used the following code to fade in only the Button Text. but it gives fadein for whole Button.
Animation animationFadeIn = AnimationUtils.loadAnimation(this, R.anim.fade_in);
//register btn listener
m_btn_register.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
m_btn_register.startAnimation(animationFadeIn);
}
});
fade_in.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="#android:anim/linear_interpolator">
<alpha
android:fromAlpha="0.1"
android:toAlpha="1.0"
android:duration="2000"
/>
</set>
what is the correct way to acheive this?
Note : Having custom spans for button does not work on lollipop and above. So have this
<Button
android:textAllCaps="false"
My CustomSpan
public class CustomSpan extends CharacterStyle implements UpdateAppearance {
private int alpha;
public int getAlpha() {
return alpha;
}
public void setAlpha(int alpha) {
this.alpha = alpha;
}
public CustomSpan() {
}
#Override
public void updateDrawState(TextPaint paint) {
paint.setAlpha(alpha);
}
}
Custom Property
private static final Property<CustomSpan, Integer> FADE_INT_PROPERTY
= new Property<CustomSpan, Integer>(Integer.class, "FADE_INT_PROPERTY") {
#Override
public void set(CustomSpan span, Integer value) {
span.setAlpha(value);
}
#Override
public Integer get(CustomSpan object) {
return object.getAlpha();
}
};
Then
String text = button.getText().toString();
final CustomSpan span = new CustomSpan();
final SpannableString spannableString = new SpannableString(text);
int start = 0;
int end = text.length();
spannableString.setSpan(span, start, end, 0);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
ObjectAnimator objectAnimator = ObjectAnimator.ofInt(
span, FADE_INT_PROPERTY, 0, 255);
objectAnimator.setEvaluator(new IntEvaluator());
objectAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
button.setText(spannableString);
}
});
objectAnimator.setDuration(10000);
objectAnimator.start();
}
});
Gif
Change your code to this way
<?xml version="1.0" encoding="UTF-8" ?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<scale android:duration="#android:integer/config_shortAnimTime"
android:pivotX="50.0%"
android:pivotY="50.0%"
android:fromXScale="1.0"
android:toXScale="0.9"
android:fromYScale="1.0"
android:toYScale="0.9"/>
<alpha android:duration="#android:integer/config_shortAnimTime"
android:fromAlpha="1.0"
android:toAlpha="0.7"/>
</set>
and one more thing declare Animation gloabal.
I don't think there is a solution using animation API because it works on the view and doesn't take care of the content of it.
So, I think you should create container view for the button and add your button background for the new container.
then set the button background to be transparent.
After that make the animation for the button only.

How to add delay between animations

I'm having a trouble with animations in android. I have my animation_char.xml:
<set xmlns:android="http://schemas.android.com/apk/res/android">
<alpha
android:duration="300"
android:fromAlpha="0.0"
android:interpolator="#android:anim/accelerate_interpolator"
android:toAlpha="1.0"/>
</set>
That is ok, but in my MainActivity I want to start an animation one after one. So I created a method to make it more easy and just change the ImageView
public void animation(ImageView imageView){
animation = AnimationUtils.loadAnimation(getApplicationContext(),R.anim.animation_char);
imageView.startAnimation(animation);
}
And for make consecutives animations, I'm trying to use AnimatorSet. But as I read AnimatorSet works with Animator, not with Animation. So my question is:
is there a way to load an animation in a animator?? Or should I use another way in order to achieve what I want to do? Thanks in advance!
EDIT
I changed my method and now Im trying with this but the problem is that all the images appear at the same time, how can I add some delay between animations?
public void animation() {
animation= AnimationUtils.loadAnimation(getApplicationContext(),R.anim.animation_char);
w.startAnimation(animation);
a.startAnimation(animation);
r.startAnimation(animation);
}
Actually I've answered on this question here. You should start your second animation in onAnimationEnd of AnimationListener of first animations. The same for second one.
You should use AnimationSet class instead of AnimatorSet.
For instance
AnimationSet as = new AnimationSet(true);
as.setFillEnabled(true);
as.setInterpolator(new BounceInterpolator());
as.addAnimation(firstAnim);
as.addAnimation(secondAnim);
as.setDuration(1000);
imageView.startAnimation(as);
I put this here maybe it helps someone...
I did something like this. I have 3 images that I want to fall one after the other.
note1 = findViewById(R.id.note1);
note1.setVisibility(View.INVISIBLE);
note2 = findViewById(R.id.note2);
note2.setVisibility(View.INVISIBLE);
note3 = findViewById(R.id.note3);
note3.setVisibility(View.INVISIBLE);
Setting visibility so that they are not shown initially
And then create 3 animations
Animation slideDown = AnimationUtils.loadAnimation(this, R.anim.slide_down);
note1.startAnimation(slideDown);
final Animation slideDown2 = AnimationUtils.loadAnimation(SplashScreen.this, R.anim.slide_down);
final Animation slideDown3 = AnimationUtils.loadAnimation(SplashScreen.this, R.anim.slide_down);
Next step is to add the event listeners that #Divers added:
slideDown.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
note1.setVisibility(View.VISIBLE);
note2.startAnimation(slideDown2);
slideDown2.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
note3.startAnimation(slideDown3);
note2.setVisibility(View.VISIBLE);
slideDown3.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
note3.setVisibility(View.VISIBLE);
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
And that's all
My animation xml is something like
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="800"
android:fromXDelta="0%"
android:fromYDelta="-50%p"
/>
<alpha
android:duration="500"
android:fromAlpha="0.1"
android:toAlpha="1.0"
/>
</set>
If you use Kotlin, you can use this way:
doOnEnd {startDelay = 1000L
start() }
Where repeatCount = 1
look at this example:
val animations = arrayOf(-140f).map { translation ->
ObjectAnimator.ofFloat(binding.viewYatch, "translationX", translation).apply {
//Update
duration = 800
repeatCount = 1
repeatMode = ObjectAnimator.RESTART
doOnEnd {
startDelay = 1000L
start()
}
}
}
val set = AnimatorSet()
set.playTogether(animations)
set.start()

setVisibility(View.GONE) doesn't disappear a view

In my activity, I have a start button, and when that's clicked it should fade out and finally disappear by setVisibility(View.GONE)
The problem is setting visibility to GONE doesn't disappear the view, it's still visible. I've purposefully made the view animation fade out to 0.1 (instead of 0) and I can see it in the background even after I've called setVisibility(View.GONE) on it.
The fadeout animation anim_fade_out.xml is:
<?xml version="1.0" encoding="utf-8"?>
<set
xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="#android:anim/linear_interpolator"
android:fillAfter="true" android:fillEnabled="true">
<alpha
android:fromAlpha="1.0"
android:toAlpha="0.1"
android:duration="200" />
</set>
The method is showTimer():
private void showTimer() {
final LinearLayout startButtonArea = (LinearLayout)findViewById(R.id.startButtonArea);
Animation animFadeOut = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.anim_fade_out);
startButtonArea.startAnimation(animFadeOut);
animFadeOut.setAnimationListener(new AnimationListener() {
#Override
public void onAnimationEnd(Animation animation) {
startButtonArea.setVisibility(View.GONE);
Log.d("Animation ended","startButtonArea SHOULD BE GONE BUT IT ISN'T");
}
#Override
public void onAnimationRepeat(Animation animation) {}
#Override
public void onAnimationStart(Animation animation) {}
});
}
To reiterate, I know that the end alpha of the animation is 0.1 (it would be 0 usually) but I want to confirm that the view is really GONE and it isn't.
Because your fillAfter is true, the animation sets the properties after your onAnimationEnd is called. You can either change fillAfter to false, or do it like this:
#Override
public void onAnimationEnd(Animation animation) {
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
startButtonArea.setVisibility(View.GONE);
Log.d("Animation ended","startButtonArea SHOULD BE GONE BUT IT ISN'T");
}
}, 0);
}

Categories

Resources