Change position of view after end of animation - android

I develop a widget based on ViewGroup and my problem is that I need to save position of items after the end of animation. I called setFillAfter(true) in my animation object I created AnimationListener and in it's onAnimationEnd method call View.layout(l,t,r,b) to set the position after animation, because I want animation to start from new item's position next time. But in this case it looks like items are layouted twice. If I don't use View.layout(l,t,r,b) at the end of animation, next animation starts from previous position. Here is my code:
private void scrollUp() {
for(int i = 0; i < getChildCount(); i++) {
final View child = getChildAt(i);
final int index = i;
final int newleft = child.getLeft() + mOffsetBetweenItems;
final int newTop = child.getTop() - mOffsetBetweenItems;
TranslateAnimation scrollUp = new TranslateAnimation(0, mOffsetBetweenItems, 0, -mOffsetBetweenItems);
scrollUp.setDuration(1500);
scrollUp.setFillAfter(true);
scrollUp.setAnimationListener(
new AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {}
#Override
public void onAnimationRepeat(Animation animation) {}
#Override
public void onAnimationEnd(Animation animation) {
child.layout(newleft, newTop, newleft + child.getMeasuredWidth(), newTop + child.getMeasuredHeight() );
}
}
);
child.startAnimation(scrollUp);
}
}
Please give me an advice how should I reset view's position accordingly to the end position of animation?

You must use ObjectAnimator , it works from API 11 level . It changes View position automatic,
here is the example
ObjectAnimator objectAnimator= ObjectAnimator.ofFloat(mContent_container, "translationX", startX, endX);
objectAnimator.setDuration(1000);
objectAnimator.start();
Thanks JUL for his answer
If your app not found object animator, change the API level from Project -> properties -> Android , than import android.animation.ObjectAnimator;

I did it. Here is the code:
private void scrollUp() {
for(int i = 0; i < getChildCount(); i++) {
final View child = getChildAt(i);
final int index = i;
final int newleft = child.getLeft() + mOffsetBetweenItems;
final int newTop = child.getTop() - mOffsetBetweenItems;
TranslateAnimation scrollUp = new TranslateAnimation(0, mOffsetBetweenItems, 0, -mOffsetBetweenItems);
scrollUp.setDuration(1500);
scrollUp.setFillEnabled(true);
scrollUp.setAnimationListener(
new AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {}
#Override
public void onAnimationRepeat(Animation animation) {}
#Override
public void onAnimationEnd(Animation animation) {
child.layout(newleft, newTop, newleft + child.getMeasuredWidth(), newTop + child.getMeasuredHeight() );
}
}
);
child.startAnimation(scrollUp);
}
}
Just removed setFillAfter(true) and write setFillEnabled(true) instead of. But in this case I don't understand the logic of setFillEnabled() working, because it provides behavior not like describes in documentation.

Reverse your animation; Start by giving your view a new position and then animate from the old position to the new position.

Related

Enlarge animation in android

I want to achieve the below animation in android I have tried scenes but scenes do not work with text as per docs it is confirmed :
"If you try to resize a TextView with an animation, the text will pop to a new location before the object has completely resized. To avoid this problem, do not animate the resizing of views that contain text."
Please any solution , the enlarged layout text can contain images too.
animation video
this thing worked some how ,but the animation is little jittery,I guess layout height final value is attained first and layoutWidth later, have to fix this. this is my enlarge/reduce animation :
public class EnlargeAnimation extends Animation {
private final int diffHeight;
private final int diffWidth;
private final int initialHeight;
private final int initialWidth;
private final View targetView;
public EnlargeAnimation(View targetView, float targetHeight, float targetWidth) {
this.targetView = targetView;
this.initialHeight = targetView.getMeasuredHeight();
this.initialWidth = targetView.getMeasuredWidth();
this.diffHeight = (int) (targetHeight-initialHeight);
this.diffWidth = (int) (targetWidth-initialWidth);
}
#Override
public boolean willChangeBounds() {
return true;
}
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
float newHeight = initialHeight + diffHeight * interpolatedTime;
float newWidth = initialWidth + diffWidth * interpolatedTime;
targetView.getLayoutParams().height = (int) newHeight;
targetView.getLayoutParams().width = (int) newWidth;
targetView.requestLayout();
}
}
this is when enlarge animation is called :
I am using viewpager so i have to make padding negative to enlarge the card size :
ValueAnimator paddingAnimator = ValueAnimator.ofInt(20, -10).setDuration(400);
paddingAnimator.setInterpolator(new LinearInterpolator());
paddingAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
int padding = (int) animation.getAnimatedValue();
view.setPadding(padding,
(int) DeviceUtils.convertDpToPx(50, v.getContext()), padding,
(int) DeviceUtils.convertDpToPx(50, v.getContext()));
view.requestLayout();
}
});
viewPagerItemSizeListener.onEnlarged();
EnlargeAnimation
enlargeAnimation =
new EnlargeAnimation(cardView, screenHeight, screenWidth);
enlargeAnimation.setDuration(400);
enlargeAnimation.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
paddingAnimator.start();
seeExampleText.setVisibility(View.INVISIBLE);
}
#Override
public void onAnimationEnd(Animation animation) {
stage.setVisibility(View.GONE);
cardEnlargedWidth = cardView.getLayoutParams().width;
cardEnlargedHeight = cardView.getLayoutParams().height;
crossContianer.setVisibility(View.VISIBLE);
detailTextContianer.setVisibility(View.VISIBLE);
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
view.startAnimation(enlargeAnimation);
I guess no one is reading it, but if something is confusing about variables let me know i will edit the answer.

TranslateAnimation not working properly

Part of the code works without problems. However, in the second, the animation happens, but not in an appropriate way.
The views that should slide jumps to their respective positions (they are going to the correct positions, but not animating properly).
Does anyone have the solution to this undesired behavior?
GIF showing the problem:
Code:
public void animateCollapse(){
final int count = getChildCount();
final int tWidth = getMeasuredWidth();
int widthSum = 0;
for (int i = 0; i < count; i++) {
final RelativeLayout child = (RelativeLayout) getChildAt(i);
widthSum += child.getWidth();
child.clearAnimation();
}
if(!mTagLayout.isCollapsed()){
//Removed piece of code, that works.
}
} else{
int currentPosX = 0;
if(tWidth> widthSum) return;
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
int lastpos = tWidth - child.getMeasuredWidth();
float value =currentPosX - child.getX();
TranslateAnimation anim = new TranslateAnimation(0, value, 0, 0);
anim.setDuration(1000);
anim.setAnimationListener(new TranslateAnimation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) { }
#Override
public void onAnimationRepeat(Animation animation) { }
#Override
public void onAnimationEnd(Animation animation)
{
isAnimating= false;
}
});
anim.setFillAfter(true);
child.startAnimation(anim);
currentPosX += child.getMeasuredWidth();
mTagLayout.setCollapsed(false);
}
}
#Edit
The views are not being destroyed and rebuilt during the animation
I fixed by using a reverse interpolator
if (mTagLayout.isCollapsed()) {
anim.setInterpolator(new ReverseInterpolator());
mTagLayout.setCollapsed(false);
} else {
mTagLayout.setCollapsed(true);
}
public class ReverseInterpolator implements Interpolator {
#Override
public float getInterpolation(float paramFloat) {
return Math.abs(paramFloat - 1f);
}
}

How to playSequentially a list of AnimatorSet?

I'm trying to make an animation of an imageview that revolves around a circle shape.
Here is the currrent code who works but without repeating the animation with different values:
public void runAnimation(){
ImageView worldView=findViewById(R.id.imageView);
int radius=worldView.getHeight()*30/70;
int centerx = worldView.getLeft()+radius;
int centery = worldView.getTop()+radius;
//List<Animator> myList = new ArrayList<>();
for (int i=0;i<360;i++) {
/*---I calculate the points of the circle---*/
int angle= (int) ((i * 2 * Math.PI) / 360);
int x= (int) (centerx+(radius*Math.cos(angle)));
int y= (int) (centery+(radius*Math.sin(angle)));
/*---Here carView is the ImageView that need to turn around the worldView---*/
ObjectAnimator animatorX =ObjectAnimator.ofFloat(carView, "x",x);
ObjectAnimator animatorY =ObjectAnimator.ofFloat(carView, "y",y);
ObjectAnimator animatorR =ObjectAnimator.ofFloat(carView, "rotation", i);
animatorX.setDuration(500);
animatorY.setDuration(500);
animatorR.setDuration(500);
AnimatorSet animatorSet=new AnimatorSet();
animatorSet.playTogether(animatorX,animatorY,animatorR);
animatorSet.start();
//myList.add(animatorSet);
}
//AnimatorSet animatorSet=new AnimatorSet();
//animatorSet.playSequentially(myList);
}
The commentary ("//") are here to illustrate what I want to create.
Thank in advance for your help.
You can add a listener to each AnimatorSet by using addListener(Animator.AnimatorListener listener).
for (int i=0;i<360;i++) {
// ...skipped some lines here...
AnimatorSet animatorSet=new AnimatorSet();
animatorSet.playTogether(animatorX,animatorY,animatorR);
myList.add(animatorSet);
animatorSet.addListener(myListener);
}
where myListener is defined as follows:
private Animator.AnimatorListener myListener = new Animator.AnimatorListener(){
#Override
public void onAnimationStart(Animator animation){
// no op
}
#Override
public void onAnimationRepeat(Animator animation){
// no op
}
#Override
public void onAnimationCancel(Animator animation){
// no op
}
#Override
public void onAnimationEnd(Animator animation){
startNextAnimation();
}
};
In addition to that, you need some variable private int counter; to iterate over the list.
Before starting the first animation, you set it to zero:
counter = 0;
myList.get(0).start();
To start the next animation (if there is one left):
private void startNextAnimation(){
counter++;
if(counter == myList.size()){
return;
}
myList.get(counter).start();
}

Animating Android ListView header height causes flicker at the end of animation

Problem
I'm trying to animate the ListView header height. I can get the animation right, but after the animation completes the ListView flickers.
Tried and failed
Use AnimationSet.setFillAfter() without changing the layout params. The animation works fine, but when you start scrolling the list, header jumps back to original position.
Use AnimationSet.setFillAfter() with new layout params applied at onAnimationEnd(). After the animation ends the header jumps to twice the required height (animated height plus the height set in layout params). When you start scrolling the list, header snaps to the required height.
Code
if (mSearchAdapter.getCount() > 0 && mListView.getChildAt(0) == mHeaderPlaceholder) {
Log.i(TAG, "Animating list view to make room for info bar");
AnimationSet slideAnimation = new AnimationSet(true);
TranslateAnimation translate = new TranslateAnimation(0, 0, 0, newHeight);
translate.setDuration(mInfoBarAnimationDuration);
translate.setInterpolator(new DecelerateInterpolator());
slideAnimation.addAnimation(translate);
slideAnimation.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
isAnimatingViewTransition = true;
}
#Override
public void onAnimationEnd(Animation animation) {
isAnimatingViewTransition = false;
final AbsListView.LayoutParams layoutParams = (AbsListView.LayoutParams) mHeaderPlaceholder.getLayoutParams();
layoutParams.height = newHeight;
mHeaderPlaceholder.setLayoutParams(layoutParams);
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
mListView.startAnimation(slideAnimation);
} else {
Log.i(TAG, "Adjusting list view header to make room for info bar");
mHeaderPlaceholder.getLayoutParams().height = newHeight;
}
I think the flicker can be avoided by listening for and overriding the events onPreDraw() or onGlobalLayout() of the ViewTreeObserver of the ListView. But I don't know exactly how I can achieve it.
Any help is much appreciated!
Instead of animating ListView header I opted to used ValueAnimator to achieve the same effect. Here is code:
if (mSearchAdapter.getCount() > 0 && mListView.getChildAt(0) == mHeaderPlaceholder) {
ValueAnimator mSlideListViewAnimator = ObjectAnimator.ofInt(from, to);
mSlideListViewAnimator.setDuration(mInfoBarAnimationDuration);
mSlideListViewAnimator.setInterpolator(new DecelerateInterpolator());
mSlideListViewAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
Integer animatedYValue= (Integer) animation.getAnimatedValue();
final AbsListView.LayoutParams layoutParams = (AbsListView.LayoutParams) mHeaderPlaceholder.getLayoutParams();
layoutParams.height = animatedYValue;
mHeaderPlaceholder.requestLayout();
}
});
mSlideListViewAnimator.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationStart(Animator animation) {
isAnimatingViewTransition = true;
}
#Override
public void onAnimationEnd(Animator animation) {
isAnimatingViewTransition = false;
}
});
mSlideListViewAnimator.start();
} else {
Log.i(TAG, "Adjusting list view header to make room for info bar");
mHeaderPlaceholder.getLayoutParams().height = newHeight;
}

Is it possible to change the destination coordinates of the imageview while animating

In my application i am able to animate the image from source location to destination location and repeating the animation 5 times using animation.setRepeatCount(5);
But i want to change the destination location(yDelta) after each repetition.
For example :
destination Ydelta is 2, after first repetition need to change the ydelta to 3 and next repetition ydelta to 4 so on... up to 5 repetitions....
Below is my animation code:
int sourceCoords[] = new int[2];
int targetCoords[] = new int[2];
int xDelta;
int yDelta;
sourceImage.getLocationOnScreen(sourceCoords);
targetImage.getLocationOnScreen(targetCoords);
xDelta = targetCoords[0] - sourceCoords[0];
yDelta = targetCoords[1] - sourceCoords[1];
sourceImage.bringToFront();
TranslateAnimation animation = new TranslateAnimation(0, xDelta, 0, yDelta);
animation.setDuration(400);
animation.setFillAfter(false);
animation.setRepeatCount(5);
sourceImage.startAnimation(animation);
animation.setAnimationListener(new AnimationListener() {
#Override
public void onAnimationStart(final Animation animation) {
sourceImage.bringToFront();
}
#Override
public void onAnimationRepeat(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
}
});

Categories

Resources