Android view animation stops when view out of screen - android

I'm having a recyclerView with several views and one is the animation view which has an animation applied to it. Once the view is out of the screen the animation is no longer active, even though the animation still exists.
The data:
rotate_around_center_point.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false" >
<rotate
android:duration="2500"
android:interpolator="#android:anim/linear_interpolator"
android:pivotX="50%"
android:pivotY="50%"
android:repeatCount="infinite"
android:repeatMode="restart"
android:toDegrees="360" />
</set>
Applying animation:
animation = AnimationUtils.loadAnimation(this.getContext(),
R.anim.rotate_around_center_point);
loadingRotatingCircleIV.startAnimation(animation);
I could not find any way to catch an event when the animation is interrupted so I'm able to restart the animation once it was out of the screen.

RecyclerView is incorrectly stopping animation on the view when view goes out from screen only if you apply View Animation to that view. If you will use Property Animation everything works properly. So the following solution will work:
ObjectAnimator animator = ObjectAnimator.ofFloat(loadingRotatingCircleIV, "rotation", 0.0f, 360.0f);
animator.setDuration(1000L);
animator.setRepeatCount(ObjectAnimator.INFINITE);
animator.setInterpolator(new LinearInterpolator());
animator.start();

If you want to use a ViewAnimation for a RecyclerView item, you have to restore animation in overriden method of RecyclerView - onViewAttachedToWindow(ItemViewHolder holder), like:
#Override
public void onViewAttachedToWindow(ItemViewHolder holder) {
super.onViewAttachedToWindow(holder);
if (holder.animated)
{
Animation anim = new ScaleAnimation(0.8f, 1.2f,
0.8f, 1.2f,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
anim.setFillAfter(true);
anim.setInterpolator(new BounceInterpolator());
anim.setDuration(1100);
anim.setRepeatCount(Animation.INFINITE);
anim.setRepeatMode(Animation.REVERSE);
holder.animatedView.startAnimation(anim);
}
}

I'm doing the exact same thing right now, and having the exact same problem. So the question is how to restart the animation once the view is back on screen.
I got the problem 99% resolved just by calling "loadingRotatingCircleIV.startAnimation(animation);" inside onBindViewHolder every time it gets called for my animated view's position.
But there's just a tiny little problem left. If you scroll down by just a little, so the view gets off screen, but it's view holder doesn't get recycled, when you scroll back up, onBindViewHolder is obviously not called again, but the animation is stopped.. So I'm still trying to fix that one..
So, my current solution:
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
...
if (position=="animated_view_position") view.startAnimation(animation);
...
}
If somebody has a better solution, please help.

create **HashMap<Integer, Boolean>** for saving each items animation loaded status
construct (){
for(int c = 0; c < adapterDataList.size(); c++){
//Here is create default status of animation loaded status used Boolean to saving
}
}
//Call Start Animation with onViewAttachedToWindow
#Override
public void onViewAttachedToWindow(ItemViewHolder holder) {
super.onViewAttachedToWindow(holder);
// get HashMap of each items Animation status like this
if(!HashMap.get(position)){ //FALSE means animation not loaded yet
//Here should call start Animation method;
} else {
//Here call no animation method, like setImageDrawable etc...
}
//create an AnimationListener for each item, when an animation is End, Listener should call a method to change HashMap above which you just created, like this **HashMap.put(position, Boolean.valueOf(true))** //TRUE means animation loaded
}
//to get position value as Integer use holder.getLayoutPosition()

Related

Flipping and changing image in ImageView

I am working on a App that is simple in work and it is working quite efficiently. But I have one place where I am looking something is not looking great and that is flipping Animation.
What I Want :
I have a Button and a ImageView beneath the button. On a Button click I want to make a Animation that it looks like ImageView has flipped and next image is shown in the ImageView. So on every click it should show next image with a flipping animation but there are some problems. I would discuss later but first let me show you how I am doing this.
What I have done so far :
flipping.xml
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:valueFrom="0" android:valueTo="180" android:propertyName="rotationY" >
</objectAnimator>
in Activity
#Override
public void onClick(View v) {
flipAnimation();
ivAnimPicture.setImageResource(myImage1);
}
private void flipAnimation(){
ObjectAnimator anim = (ObjectAnimator) AnimatorInflater.loadAnimator(this, R.animator.flipping);
anim.setTarget(ivAnimPicture);
anim.setDuration(1500);
anim.start();
}
Problem
When It rotates to 180 from 0 , when it comes exactly at 90 degree we can see image view edges so it makes the animation look not so good. and Also the image changes first then the Flipping animation starts where as I want that Flipping animation should start and in the middle of it the new image should appear. so when the animation stops there should be surprisingly new image for the user.
So I really do not want Image to set in the image-view and then the Animation starts and Animate the image view
Please suggest me more good way or if there is library which is not obsolete.
Chathuranga's solution will do the job. but you better:
1.Use ViewPropertyAnimator. Specially, when you need to perform different animations on several ImageViews.
2.rotate from 270f to 360f for second flip, otherwise your image will be mirrored.
3.Load your second Image into a Drawable before starting the animation, to have a smooth rotation.
final Drawable drawable=getResources().getDrawable(R.drawable.a);
final ImageView iv = ((ImageView)findViewById(R.id.imageView1));
iv.setRotationY(0f);
iv.animate().rotationY(90f).setListener(new AnimatorListenerAdapter()
{
#Override
public void onAnimationEnd(Animator animation)
{
iv.setImageDrawable(drawable);
iv.setRotationY(270f);
iv.animate().rotationY(360f).setListener(null);
}
});
I was in your situation trying to figure out how to get this animation done. Here's how I achieve this.
you need to define two animations. one to rotate from 0 degree to 90 degree and other for to rote from 90 degree to 180 degree
flipstage1.xml
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:propertyName="rotationY"
android:valueFrom="0"
android:valueTo="90">
</objectAnimator>
flipstage2.xml
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:propertyName="rotationY"
android:valueFrom="90"
android:valueTo="180">
</objectAnimator>
Place these two files under res/animator
In your code start first animation first, add a listener to it. On animation end change the image and start second animation.
ObjectAnimator animStage1 = (ObjectAnimator) AnimatorInflater.loadAnimator(getActivity(), R.animator.flipstage1);
final ObjectAnimator animStage2 = (ObjectAnimator) AnimatorInflater.loadAnimator(getActivity(), R.animator.flipstage2);
animStage1.setTarget(imageIcon1);
animStage2.setTarget(imageIcon1);
animStage1.setDuration(500);
animStage2.setDuration(500);
animStage1.start();
animStage1.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animation) {
}
#Override
public void onAnimationEnd(Animator animation) {
animStage2.start();
imageIcon1.setImageDrawable(ResourcesCompat.getDrawable(view.getResources(),R.drawable.okicon,null));
}
#Override
public void onAnimationCancel(Animator animation) {
}
#Override
public void onAnimationRepeat(Animator animation) {
}
});
imageIcon1 is the reference to image view in xml layout.
Try this simple piece of code and let me know
ObjectAnimator anim = (ObjectAnimator) AnimatorInflater.loadAnimator(this, R.animator.flipping);
anim.setTarget(ivAnimPicture);
anim.setDuration(1500);
anim.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
ivAnimPicture.setImageResource(myImage1);
}
});
anim.start();

rotate a refresh button in ListView

recently I wrote a function.it's about a refresh button in each list item. what I want is click the button or List Item, the refresh button starts rotate. stops when the request finished.
I use animation as follows:
<?xml version="1.0" encoding="UTF-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1000"
android:fillAfter="true"
android:fromDegrees="0"
android:interpolator="#android:anim/linear_interpolator"
android:pivotX="50%"
android:pivotY="50%"
android:repeatCount="infinite"
android:toDegrees="358" />
and some source code are here:
public void refresh(View v) {
Animation rotation = AnimationUtils.loadAnimation(mContext,
R.anim.rotate);
rotation.setFillAfter(true);
v.startAnimation(rotation);
}
public void completeRefresh(View v) {
v.clearAnimation();
}
when the request finished, I call notifyDataSetChanged() to refresh the LiseView.
the problem is that the button was indeed rotating. but when I click it the second time. it's rotating but a little fuzzy. just like this:
any suggestions? thanks a lot.
What is most likely happening on your second (and subsequent clicks) is that the animation is running on it again.
In your current implementation, try using setTag(...) like this:
public void refresh(View v) {
if(v.getTag() != null && (boolean)v.getTag()) {
//do nothing, since we are setting the tag to be true once pressed
} else {
//this view hasn't been clicked yet, show animation and set tag
v.setTag(true);
Animation rotation = AnimationUtils.loadAnimation(mContext, R.anim.rotate);
rotation.setFillAfter(true);
v.startAnimation(rotation);
}
}
In your Adapter, you should keep track of which list items are being animated (I'm assuming multiple items can be clicked at the same time). Once you know that the 'request' is finished, you can update the adapter with the correct items and then call notifyDataSetChanged()

Trouble with clicking after layout animation

I have a ListView on screen and a menu at the bottom. Upon a click of menu key, it animates-slides off the screen and the ListView expands.
menuBtmVisable = false;
Animation menu_off = AnimationUtils.loadAnimation(this, R.anim.menu_off);
menubtm.startAnimation(menu_off);
Display display = getWindowManager().getDefaultDisplay();
LayoutParams listlp = new LayoutParams(display.getWidth(), display.getHeight()-87 , 0, 50);
ListViewMain.setLayoutParams(listlp);
menu_off.xml
<set
android:fillEnabled="true"
android:fillAfter="true"
xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:fromYDelta="0"
android:toYDelta="120"
android:duration="500"
/>
</set>
Yet when, with the menu down, I click on the ListView item "13" ( see picture ), it results in a menu click, as if it is still in place...
What do you think would be the best way to take care of it?
I've looking for an answer for a problem like that, and finally, after a week, I've managed to solve my problem. Since it looks similar to yours, maybe it will help you.
Set up and AnimationListener() in your animation and, onAnimationEnd, change the layout as you want. In my case, I wanted to slide a layout up, so 2 buttons would appear from below. However, the layout just slided visually; the buttons would still be off screen, interactionally speaking. So I have something like this:
final View screen = findViewById(R.id.welcome_screen);
final Animation a = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.slide_home_up);
a.setFillAfter(true);
a.setAnimationListener(new AnimationListener() {
public void onAnimationStart(Animation animation) {
}
public void onAnimationRepeat(Animation animation) {
}
public void onAnimationEnd(Animation animation) {
screen.clearAnimation();
screen.setPadding(0, -222, 0, 0);
}
});
screen.startAnimation(a);

Android Animation

I trying to move a image from one place to other using animation,but after moving it coming back to original position, how to stop it to the moved position itself.
to let the image in the last place of the animation , try this :
TranslationAnimation ta = new TranslateAnimation(fromX, toX, 0, 0);
ta.setDuration(1000);
ta.setFillAfter(true); // this will let the image in the last place of the Animation
imageView.startAnimation(ta);
After an Animation is done, use the method setFillAfter(true), to make the last animation state persist:
If fillAfter is true, the transformation that this animation performed will persist when it is finished.
Animation.setFillAfter/Before - Do they work/What are they for?
If you need to do something more specific, you could also set an animation listener and move your object at the end of the animation:
animation1.setAnimationListener(new AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
//change according to your needs
myView.setX(0);
}
#Override
public void onAnimationRepeat(Animation animation) { }
});
Finally got a way to work around,the right way to do this is setFillAfter(true),
if you want to define your animation in xml then you should do some thing like this
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="#android:anim/decelerate_interpolator"
android:fillAfter="true">
<translate
android:fromXDelta="0%"
android:toXDelta="-100%"
android:duration="1000"/>
</set>
you can see that i have defined filterAfter="true" in the set tag,if you try to
define it in translate tag it won't work,might be a bug in the framework!!
and then in the Code
Animation anim = AnimationUtils.loadAnimation(this, R.anim.slide_out);
someView.startAnimation(anim);
See this blog post for a solution:
// first set the view's location to the end position
view.setLayoutParams(...); // set to (x, y)
// then animate the view translating from (0, 0)
TranslationAnimation ta = new TranslateAnimation(-x, -y, 0, 0);
ta.setDuration(1000);
view.startAnimation(ta);
I'm sure you would have found the answer by now (I just did... so I am posting for others). Android seems to have officially shifted to a new animation framework called "Property Animation". This has been available since Honeycomb (3.0). This will essentially solve your problem as it animates the actual property values.
DEV GUIDE:
http://developer.android.com/guide/topics/graphics/prop-animation.html

Android: Updating a LinearLayout position after animation is complete

Any help with the following problem would be greatly appreciated. I know what I need to do and I have checked the Developer docs, but the exact syntax I need to use eludes me (I'm a noob).
Here's what I'm doing. I have a translate.xml file in res/anim that works fine. It looks like this:
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXDelta="0%"
android:toXDelta="0%"
android:fromYDelta="0%"
android:toYDelta="10%"
android:repeatCount="0"
android:duration="1000"
android:fillEnabled="true"
android:fillAfter="true"/>
I'm executing my code like this:
l = (LinearLayout) findViewById(R.id.linearLayout1);
a = AnimationUtils.loadAnimation(this, R.anim.translate);
a.setAnimationListener(new AnimationListener() {
public void onAnimationStart(Animation anim){};
public void onAnimationRepeat(Animation anim){};
public void onAnimationEnd(Animation anim){
//l.setLayoutParams(params);
};
});
l.startAnimation(a);
When the animation is done I would like the LinearLayout it animated to move to it's new position (where the animation moved it to). The reason for this is the LinearLayout contains several form elements the user can interact with.
This is a real simple animation for a fairly simple project. It simply moves the element about 30 pixels down the screen. I wouldn't ask for help except I've been struggling with this for several hours now. I know I need to update the LinearLayout's parameters on the end of the animation, but how exactly? I've read of several different ways and they're all a bit confusing.
Thanks in advance.
Instead of creating a new AnimationListener, try implementing the AnimationListener interface to your current (or a new) class. Then just override the onAnimationEnd() method.
Example:
public class ThisClass implements AnimationListener {
private otherMethod() {
l.getAnimation().setAnimationListener(this);
}
public void onAnimationStart(Animation anim){};
public void onAnimationRepeat(Animation anim){};
public void onAnimationEnd(Animation anim){
l.setLayoutParams(params);
};
}
Finally got a way to work around,the right way to do this is setFillAfter(true),
if you want to define your animation in xml then you should do some thing like this
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="#android:anim/decelerate_interpolator"
android:fillAfter="true">
<translate
android:fromXDelta="0%"
android:toXDelta="-100%"
android:duration="1000"/>
</set>
you can see that i have defined filterAfter="true" in the set tag,if you try to define it in translate tag it won't work,might be a bug in the framework!!
and then in the Code
Animation anim = AnimationUtils.loadAnimation(this, R.anim.slide_out);
someView.startAnimation(anim);
OR
TranslateAnimation animation = new TranslateAnimation(-90, 150, 0, 0);
animation.setFillAfter(true);
animation.setDuration(1800);
someView.startAnimation(animation);
then it will surely work!!
Now this is a bit tricky it seems like the view is actually move to the new position but actually the pixels of the view are moved,i.e your view is actually at its initial position but not visible,you can test it if have you some button or clickable view in your view(in my case in layout),to fix that you have to manually move your view/layout to the new position
public TranslateAnimation (float fromXDelta, float toXDelta, float fromYDelta, float toYDelta)
new TranslateAnimation(-90, 150, 0, 0);
now as we can see that our animation will starts from -90 x-axis to 150 x-axis
so what we do is set
someView.setAnimationListener(this);
and in
public void onAnimationEnd(Animation animation)
{
someView.layout(150, 0, someView.getWidth() + 150, someView.getHeight());
}
now let me explain public void layout (int left, int top, int right, int botton)
it moves your layout to new position first argument define the left,which we is 150,because translate animation has animated our view to 150 x-axis, top is 0 because we haven't animated y-axis,now in right we have done someView.getWidth() + 150 basically we get the width of our view and added 150 because we our left is now move to 150 x-axis to make the view width to its originall one, and bottom is equals to the height of our view.
I hope you people now understood the concept of translating, and still you have any questions you can ask right away in comment section,i feel pleasure to help :)
EDIT Don't use layout() method as it can be called by the framework when ever view is invalidated and your changes won't presist, use LayoutParams to set your layout parameters according to your requirement

Categories

Resources