Animation method applyTransformation not triggered until I click any layout - android

This is so weird, I've this animation code:
public class ExpandAnimation extends Animation {
private View mAnimatedView;
private MarginLayoutParams mViewLayoutParams;
private int mMarginStart, mMarginEnd;
private boolean mWasEndedAlready = false;
/**
* Initialize the animation
* #param view The layout we want to animate
* #param duration The duration of the animation, in ms
*/
public ExpandAnimation(View view, int duration) {
setDuration(duration);
mAnimatedView = view;
mViewLayoutParams = (MarginLayoutParams) view.getLayoutParams();
mMarginStart = mViewLayoutParams.rightMargin;
mMarginEnd = (mMarginStart == 0 ? (0- view.getWidth()) : 0);
view.setVisibility(View.VISIBLE);
mAnimatedView.requestLayout();
}
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
super.applyTransformation(interpolatedTime, t);
if (interpolatedTime < 1.0f) {
// Calculating the new bottom margin, and setting it
mViewLayoutParams.rightMargin = mMarginStart
+ (int) ((mMarginEnd - mMarginStart) * interpolatedTime);
// Invalidating the layout, making us seeing the changes we made
mAnimatedView.requestLayout();
// Making sure we didn't run the ending before (it happens!)
} else if (!mWasEndedAlready) {
mViewLayoutParams.rightMargin = mMarginEnd;
mAnimatedView.requestLayout();
mWasEndedAlready = true;
}
}
}
And I use this Animation:
View parent = (View) v.getParent();
View containerMenu = parent.findViewById(R.id.containerMenu);
ExpandAnimation anim=new ExpandAnimation(containerMenu, 1000);
containerMenu.startAnimation(anim);
This animation toggle a layout hidding / showing it.
By default, its hidden. When I click, animation works and it's shown. When I click again, it shrinks correctly. But the 3rd time, it does nothing. I've debugged and I found out that the constructor is called but not applyTransformation.
Somehow, if I click any layout around the screen, the animation suddenly starts.
Any idea?
Edit
Does anyone know WHEN is applyTransformation triggered?

I can't understand why, but when I click or do any action to any layout, the animation finally starts. So I programatically added a workaround. I've a scrollview in my layout, so I move the scroll position:
hscv.scrollTo(hscv.getScrollX()+1, hscv.getScrollY()+1);
This just after containerMenu.startAnimation(anim);
This just works, I can't understand why.
Also, I found out that some animations worked flawless on android > 4, but on 2.3 for instance, it had the same issue, worked to expand, and to shrink, but not to expand for the second time.
parent.invalidate();
Did the trick.

Related

ChangeBounds Android Transition

I have a recyclerview in my app, and each row contains a button which shows a text in the same cell, under the button. I have used ChangeBounds transition to make the text appear with a smooth animation, increasing the row height until the text is completely shown. So when a button is clicked, I do:
TransitionManager.beginDelayedTransition(row, transition)
holder.hiddenText.setVisibility(View.VISIBLE)
It works well, but whith a problem. The hidden text appears with an animation which increases its height, as expected. But the row height is not animated, and it jumps from the original height until the final height without any animation.
Is there any way to achieve a height transition over the row, to increase at the same time as the text?
If you want animation to take effect for row also, then you need to perform beginDelayedTransition() on a one layer higher of the row, which in your case maybe is the actual RecyclerView.
Try this on your row's layout
public static void expand(final View v) {
v.measure(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
final int targetHeight = v.getMeasuredHeight();
// Older versions of android (pre API 21) cancel animations for views with a height of 0.
v.getLayoutParams().height = 1;
v.setVisibility(View.VISIBLE);
Animation a = new Animation()
{
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
v.getLayoutParams().height = interpolatedTime == 1
? LayoutParams.WRAP_CONTENT
: (int)(targetHeight * interpolatedTime);
v.requestLayout();
}
#Override
public boolean willChangeBounds() {
return true;
}
};
// 1dp/ms
a.setDuration((int)(targetHeight / v.getContext().getResources().getDisplayMetrics().density));
v.startAnimation(a);
}
Linear or Relative layout of row's will animate and expand. Hope this solves your problem

How to change a View's height in ListView and don't make its child re-layout?

I need to implement this things, a height of item in ListView will be reduced slowly, when its height reduce to 0, it's gone. On this process, the remain views that below the item, should move up slowly.
At First, I use the ObjectAnimator to change the 'scaleY', but the size of item occupy was not changed, when Animator ends, ListView refresh, the empty rectangle was gone.
ObjectAnimator oa = ObjectAnimator.ofFloat(itemView, 'scaleY', 1f, 0f);
And I found another way to do this, I write a Runnable to change the height of the item, but there are some child view in my item, like a ImageView, with the height changing, the ImageView changing too, I think this is not look well.
LayoutParams lp = itemView.getLayoutParams();
lp.height = newHeight;
itemView.setLayoutParams(lp);
At last, I found third way to do, change the 'bottom' value of the item, yes, It looks like a window with reducing height, but height not changed, the remain views that below the item didn't move until Runnable ends and ListView refresh.
itemView.setBottom(itemView.getTop() + newHeight);
How to solve this?
I do something similar to this and work fine:
public void collapse(final View v, final int toHeight, final int toWidth) {
final int initialHeight = v.getMeasuredHeight();
Animation a = new Animation() {
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
v.getLayoutParams().height = (int) (toHeight * interpolatedTime);
v.getLayoutParams().width = (int) (toWidth * interpolatedTime);
v.requestLayout();
}
#Override
public boolean willChangeBounds() {
return true;
}
};
// 1dp/ms
a.setDuration(ANIMATION_DURATION);
a.setInterpolator(new AccelerateInterpolator());
v.startAnimation(a);
}
the height set in the layout can not be fixed (put wrap_content). Hope it help you!!

How to clip Transition Animation to draw only with in the Child view?

I am running a transition animation for a view in an activity to come from top of the screen to bottom. which is coming on top of the title view of the screen. How can i apply the animation only with in the view(respective to child only) or from a specific Y or X position?
I am using the below code
XML Code
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="#android:anim/accelerate_interpolator">
<translate android:fromYDelta="-100%p" android:toYDelta="0" android:duration="500" />
</set>
Java Code
Animation in = AnimationUtils.loadAnimation(_activity, R.anim.in_from_top);
view.setAnimation(in);
Now this view is coming from the top of the screen. I want the animation to be started at specific X,Y point instead of top of the screen. The animated view is coming on top of the Title of the Activity which is a flaw as per my requirement.
You will need to create a Custom Animation class something like this :
public class ExpandAnimation extends Animation {
private View mAnimatedView;
private LayoutParams mViewLayoutParams;
private int mMarginStart, mMarginEnd;
private boolean mIsVisibleAfter = false;
private boolean mWasEndedAlready = false;
/**
* Initialize the animation
*
* #param view
* The layout we want to animate
*
* #param duration
* The duration of the animation, in ms
*/
public ExpandAnimation(View view, int duration) {
setDuration(duration);
mAnimatedView = view;
mViewLayoutParams = (LayoutParams) view.getLayoutParams();
mIsVisibleAfter = (mViewLayoutParams.bottomMargin == 0);
mMarginStart = mViewLayoutParams.bottomMargin;
mMarginEnd = (mMarginStart == 0 ? (0 - view.getHeight()) : 0);
view.setVisibility(View.VISIBLE);
}
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
super.applyTransformation(interpolatedTime, t);
if (interpolatedTime < 0.5f) {
mViewLayoutParams.bottomMargin = mMarginStart + (int) ((mMarginEnd - mMarginStart) * interpolatedTime);
mAnimatedView.requestLayout();
} else if (!mWasEndedAlready) {
mViewLayoutParams.bottomMargin = mMarginEnd;
mAnimatedView.requestLayout();
if (mIsVisibleAfter) {
mAnimatedView.setVisibility(View.GONE);
}
mWasEndedAlready = true;
}
}
}
And then apply this animation on the x,y co-ordinate where you want.
Suppose for say you have a button at some x,y co-ordinate and on its click we animate a view and then scroll it back. You will have to do something like this :
private View previous = null;
private void doTransformation() {
if (previous != null) {
((LinearLayout.LayoutParams) previous.getLayoutParams()).bottomMargin = -200;
ExpandAnimation anim = new ExpandAnimation(previous, 300);
previous.startAnimation(anim);
previous = null;
} else {
View yourlayout= findViewById(R.id.your_layout);
ExpandAnimation anim = new ExpandAnimation(yourLayout, 300);
detailLayout.startAnimation(anim);
previous = yourLayout;
}
}
If you have added the two childrens to a single parent then this issues occurs. Add the children to an another layout and then add this layout to the actual layout. This will resolve your issue.
You can try animation from java code only as
Animation animation1=new TranslateAnimation(0.0f, 0.0f, 10.0f, 250.0f);
animation1.setDuration(5000);
view.startAnimation(animation1);
and you can set your X and Y coordinates in TranslateAnimation(fromX, toX, fromY, toY) as I have done in above code.

ListView within a listview

I have a parent ListView shown with items based on a custom layout. When a user clicks on any item then I need to add a child ListView to that item and should display the overall item of the parent ListView with expanding animation. [All data need to be added dynamically]
Any suggestions....
Simple you can add your item in a layout (via xml or code) and show(hide) with animation. Here is example from Udinic. It had listview item expand with animation and require API level only 4+.
This example's so simple. You only define your item in linearlayout called toolbar
ExpandAnimationExample
in onItemClick event use ExpanAnimation
/**
* This animation class is animating the expanding and reducing the size of a view.
* The animation toggles between the Expand and Reduce, depending on the current state of the view
* #author Udinic
*
*/
public class ExpandAnimation extends Animation {
private View mAnimatedView;
private LayoutParams mViewLayoutParams;
private int mMarginStart, mMarginEnd;
private boolean mIsVisibleAfter = false;
private boolean mWasEndedAlready = false;
/**
* Initialize the animation
* #param view The layout we want to animate
* #param duration The duration of the animation, in ms
*/
public ExpandAnimation(View view, int duration) {
setDuration(duration);
mAnimatedView = view;
mViewLayoutParams = (LayoutParams) view.getLayoutParams();
// decide to show or hide the view
mIsVisibleAfter = (view.getVisibility() == View.VISIBLE);
mMarginStart = mViewLayoutParams.bottomMargin;
mMarginEnd = (mMarginStart == 0 ? (0- view.getHeight()) : 0);
view.setVisibility(View.VISIBLE);
}
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
super.applyTransformation(interpolatedTime, t);
if (interpolatedTime < 1.0f) {
// Calculating the new bottom margin, and setting it
mViewLayoutParams.bottomMargin = mMarginStart
+ (int) ((mMarginEnd - mMarginStart) * interpolatedTime);
// Invalidating the layout, making us seeing the changes we made
mAnimatedView.requestLayout();
// Making sure we didn't run the ending before (it happens!)
} else if (!mWasEndedAlready) {
mViewLayoutParams.bottomMargin = mMarginEnd;
mAnimatedView.requestLayout();
if (mIsVisibleAfter) {
mAnimatedView.setVisibility(View.GONE);
}
mWasEndedAlready = true;
}
}
}
Detail usage is in project.
Instead of using a second ListView, you might want to consider using just a simple LinearLayout and populating it dynamically (toggling its visibility with View.VISIBLE and View.GONE). From what I know you shouldn't nest ListViews.

Slide expand animation in android

I have a simple ListView listing results in android. Upon click of each item, I would like it to slide down expand and show the content. Is there an easy way to do this in android?
Any help will be appreciated.
Here is example from Udinic. It had listview item expand with animation and require API level only 4+
Basically you need a animation class
/**
* This animation class is animating the expanding and reducing the size of a view.
* The animation toggles between the Expand and Reduce, depending on the current state of the view
* #author Udinic
*
*/
public class ExpandAnimation extends Animation {
private View mAnimatedView;
private LayoutParams mViewLayoutParams;
private int mMarginStart, mMarginEnd;
private boolean mIsVisibleAfter = false;
private boolean mWasEndedAlready = false;
/**
* Initialize the animation
* #param view The layout we want to animate
* #param duration The duration of the animation, in ms
*/
public ExpandAnimation(View view, int duration) {
setDuration(duration);
mAnimatedView = view;
mViewLayoutParams = (LayoutParams) view.getLayoutParams();
// decide to show or hide the view
mIsVisibleAfter = (view.getVisibility() == View.VISIBLE);
mMarginStart = mViewLayoutParams.bottomMargin;
mMarginEnd = (mMarginStart == 0 ? (0- view.getHeight()) : 0);
view.setVisibility(View.VISIBLE);
}
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
super.applyTransformation(interpolatedTime, t);
if (interpolatedTime < 1.0f) {
// Calculating the new bottom margin, and setting it
mViewLayoutParams.bottomMargin = mMarginStart
+ (int) ((mMarginEnd - mMarginStart) * interpolatedTime);
// Invalidating the layout, making us seeing the changes we made
mAnimatedView.requestLayout();
// Making sure we didn't run the ending before (it happens!)
} else if (!mWasEndedAlready) {
mViewLayoutParams.bottomMargin = mMarginEnd;
mAnimatedView.requestLayout();
if (mIsVisibleAfter) {
mAnimatedView.setVisibility(View.GONE);
}
mWasEndedAlready = true;
}
}
}
And use this :
View toolbar = view.findViewById(R.id.toolbar);
// Creating the expand animation for the item
ExpandAnimation expandAni = new ExpandAnimation(toolbar, 500);
// Start the animation on the toolbar
toolbar.startAnimation(expandAni);
ExpandAnimationExample
check out this answer. more than that you have to use the tweed animation. check the ApiDemos/Animation2 Examples. and also see the anim folder in ApiDemos. it helps a lot to me. according to your question slide_top_to_bottom will help.
The simplest way is to use an ObjectAnimator
ObjectAnimator animation = ObjectAnimator.ofInt(yourTextView, "maxLines", 40);
animation.setDuration(200).start();
This will change maxLines from your TextView to 40, over 200 milliseconds.
Beware of using yourTextView.getLineCount() to determine how many lines to expand to, because it wont give an accurate figure until after a layout pass. I recommend you just hard code a maxLines value that's longer than you expect the text would ever be. You could also estimate it using yourTextView.length() divided by the lowest number of characters you'd ever expect per line.

Categories

Resources