ChangeBounds Android Transition - android

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

Related

How to smoothen Linear layout height animation, having heavy content

Animation animation = new Animation() {
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
ViewGroup.LayoutParams params = slidingPane.getLayoutParams();
int calculatedHeight = expandedHeight - ((int) (expandedHeight * interpolatedTime));
if (calculatedHeight <= collapsedHeight) {
calculatedHeight = collapsedHeight;
}
params.height = calculatedHeight;
slidingPane.setLayoutParams(params);
slidingPane.requestLayout();
}
#Override
public boolean willChangeBounds() {
return true;
}
};
animation.setDuration(ANIMATION_DURATION);
animation.setAnimationListener(animationListener);
slidingPane.startAnimation(animation);
SlidingPane is a LinearLayout and it has a ListView as a child. ListView contains images in every row.
Now this code is working absolutely fine, but animation is not smooth. If I remove images from listview then it works fine.
I have already tried following things based on the answers on SO on similar questions -
1. Hide the content of sliding pane before animation and then again make them visible on animation end. It helps but behavior looks very odd
2. Set android:animateLayoutChanges="true" in xml, but its not animating anything
Is there anyway to solve this problem?
Instead of manually changing the height on each animation step, you should try to use the more systematic animation, like ValueAnimator, or ObjectAnimator:
slidingPane.animate().scaleY(0f).setInterpolator(new AccelerateDecelerateInterpolator()).setDuration(ANIMATION_DURATION);
You can use pivotY/pivotY on the view to control the anchor point of the scale animation.
Related docs:
https://developer.android.com/reference/android/animation/ValueAnimator.html
https://developer.android.com/reference/android/animation/ObjectAnimator.html
https://developer.android.com/guide/topics/graphics/prop-animation.html

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!!

Custom ListView with animated visibility toggle

I have a Custom Listview with a lot of text in it.. I'd like that when I click on the the ListView other text will appear under the clicked row.. I managed to do this set the TextView to GONE in the custom_row.xml and then in the ClickListener set it to VISIBLE.. But this is too glitching and so I'd like to make a toggle animation like JQUERY's blind show...
How can I make this with an animation in Android ?
You can create your own Animation and change height of item, like:
public class ExpandAnimation extends Animation {
...
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
super.applyTransformation(interpolatedTime, t);
if (interpolatedTime < 1.0f) {
viewLayoutParams.height = heightStart +
(int) (( heightEnd - heightStart) * interpolatedTime);
animatedView.requestLayout();
}
}
}
And set this animation on item when it's clicked.
Use a ValueAnimator to change the height of ListView from 0 to final height.
You can find a very good example in this tutorial
The code would be as follows:
ValueAnimator animator = ValueAnimator.ofInt(intialHeight, finalHeight);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator v) {
int value = (Integer) v.getAnimatedValue(); // get the most recent value calculated by the ValueAnimator
ViewGroup.LayoutParams lp = yourLayout.getLayoutParams(); // get the height of your ListView
lp.height = value; //change the height
mLinearLayout.setLayoutParams(layoutParams); //update it to the view
}
animator.start(); //start the animation

Scaling a right aligned layout doesn't work as expected

I have a RelativeLayout with a ImageView inside it, it is aligned to the right of the screen with
android:layout_alignParentRight="true"
I then apply an animation to the layout, that will scale it to twice it size (on X-axis), but for some reason the alignment is broken and the layout (and image within it) stretches outside of the screen to the right. I was expecting it to grow to the left since it is aligned to the parent right.
I guess I could apply a translate to -X at the same time, but there are problems with this as well (1. it´s a bit complicated to compute, 2. the fillAfter never seems to work when using an AnimationSet).
Does anyone know how to solve this problem smoothly? :)
Apparently, Androids scaling is doing all sorts of bad stuff, for example it does not scale a 9-patch correct. Here is a custom animation for scaling that will solve the above and is compatible with 9-patch images. I also got some info here for the basics, this is just a rewrite of his solution: How to implement expandable panels in Android?
public class ExpandAnimation extends Animation
{
private final int mStartWidth;
private final int mDeltaWidth;
private View view;
public ExpandAnimation(View view, int startWidth, int endWidth)
{
mStartWidth = startWidth;
mDeltaWidth = endWidth - startWidth;
this.view = view;
}
#Override
protected void applyTransformation(float interpolatedTime, Transformation t)
{
android.view.ViewGroup.LayoutParams lp = view.getLayoutParams();
lp.width = (int) (mStartWidth + mDeltaWidth * interpolatedTime);
view.setLayoutParams(lp);
view.invalidate();
}
#Override
public boolean willChangeBounds()
{
return true;
}
}

Animation method applyTransformation not triggered until I click any layout

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.

Categories

Resources