Is it possible to animate a layout_weight change of a View?
I have tried:
ObjectAnimator anim = ObjectAnimator.ofFloat(headerRoot,
"layout_weight", ws, 1f);
anim.setDuration(1500);
anim.addUpdateListener(this);
anim.start();
This has no effect on my layout. Is the objectAnimator able to manipulate the layout_weight property of a view?
Just use a class provided here: https://stackoverflow.com/a/20334557/1763138
private class ExpandAnimation extends Animation {
private final float mStartWeight;
private final float mDeltaWeight;
public ExpandAnimation(float startWeight, float endWeight) {
mStartWeight = startWeight;
mDeltaWeight = endWeight - startWeight;
}
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) mContent.getLayoutParams();
lp.weight = (mStartWeight + (mDeltaWeight * interpolatedTime));
mContent.setLayoutParams(lp);
}
#Override
public boolean willChangeBounds() {
return true;
}
}
and change mContent to your headerRoot
This has no effect on my layout. Is the objectAnimator able to manipulate the layout_weight property of a view?
No, it is not. ObjectAnimator uses the setter method of an object to update its value. A LayoutParam has not setWeight method, it only has the weight property you can change.
It's all explained here: http://developer.android.com/guide/topics/graphics/prop-animation.html#object-animator.
Related
I'm trying to animate the height of a ConstraintLayout using the Animation class, and the setDuration method doesn't seem to be working. The height is just instantly changed to the desired height value. I've seen posts about animations being disabled in the developer options, but that's not the problem, it's set to 1x. Anyway, code is below:
public static void scaleUp() {
Animation animation = new Animation() {
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
ConstraintLayout.LayoutParams params = (ConstraintLayout.LayoutParams) profileLayout.getLayoutParams();
// modify your layout params here
params.height = 10;
profileLayout.setLayoutParams(params);
}
};
animation.setDuration(300); // in ms
profileLayout.startAnimation(animation);
}
Instead of params.height = 10; use params.height = (int)(10.0 * interpolatedTime).
Append profileLayout.requestLayout(); at the end of your applyTransformation method. This is used to update the layout on a screen.
Possible Solutions:
Answered Here
Medium Article About Animating
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!!
I am doing translate animation using object animator. After successful translation I was trying to retain the location of animation using setting up new layoutparams. But on animation end when I set existing layoutparams without changing any margin view retains its location and working perfectly.
private void IndicatorAnimation(View currentView){
final FrameLayout fl = (FrameLayout)findViewById(R.id.indicator);
RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) fl.getLayoutParams();
final int[] origin = new int[2];
fl.getLocationInWindow(origin);
final int[] destination = new int[2];
currentView.getLocationInWindow(destination);
ObjectAnimator oa = ObjectAnimator.ofFloat(fl, "translationX", origin[0], destination[0]);
oa.setDuration(300);
oa.start();
oa.addListener(new AnimatorListener() {
#Override
public void onAnimationStart(Animator animation) {
}
#Override
public void onAnimationRepeat(Animator animation) {
}
#Override
public void onAnimationEnd(Animator animation) {
RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) fl.getLayoutParams();
fl.setLayoutParams(lp);
}
#Override
public void onAnimationCancel(Animator animation) {
}
});
}
My Question is how it is possible? Because getLayoutparams at animation end gives me same parameters which were there before animation starts.
There are actual properties that belong to the [View.TransformationInfo][1] class which include mTranslationX and mTranslationY. This is basically how the View keeps track of this information, not by updating the LayoutParams.
The TransformationInfo class is not publicly available, but (on API 14) you are able to use the View's properties of X, Y, etc. to get this information. onAnimationEnd you could reset those values and set the LayoutParams margins to accommodate (this of course depends on your layout how to be accomplish this).
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
I have two views in a linear layout, I programmatically change their layout_weight property. Is there a way I could animate this change in weight so when the weight is changed views slides towards a new size?
You can simply use ObjectAnimator.
ObjectAnimator anim = ObjectAnimator.ofFloat(
viewToAnimate,
"weight",
startValue,
endValue);
anim.setDuration(2500);
anim.start();
The one problem is that View class has no setWeight() method (which is required by ObjectAnimator). To address this I wrote simple wrapper which helps archive view weight animation.
public class ViewWeightAnimationWrapper {
private View view;
public ViewWeightAnimationWrapper(View view) {
if (view.getLayoutParams() instanceof LinearLayout.LayoutParams) {
this.view = view;
} else {
throw new IllegalArgumentException("The view should have LinearLayout as parent");
}
}
public void setWeight(float weight) {
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) view.getLayoutParams();
params.weight = weight;
view.getParent().requestLayout();
}
public float getWeight() {
return ((LinearLayout.LayoutParams) view.getLayoutParams()).weight;
}
}
Use it in this way:
ViewWeightAnimationWrapper animationWrapper = new ViewWeightAnimationWrapper(view);
ObjectAnimator anim = ObjectAnimator.ofFloat(animationWrapper,
"weight",
animationWrapper.getWeight(),
weight);
anim.setDuration(2500);
anim.start();
I have been looking at this as well. Eventually I solved it by animating the weightsum property of the parent, which works very nice if you have two views in a LinearLayout.
see:
Animating weightSum property using ObjectAnimator
In the example below, if you animate the weightSum from 1.0 to 2.0, Screen 2 will animate nicely into view.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/dual_pane"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal"
android:weightSum="1.0">
<!-- Screen 1 -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:background="#ff0000"
android:layout_weight="1">
</LinearLayout>
<!-- Screen 2 -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:background="#ff6600"
android:layout_weight="1">
</LinearLayout>
</LinearLayout>
Note: I am not sure that this is the best way, but I tried it and it's working fine
Simply using ValueAnimator
ValueAnimator m1 = ValueAnimator.ofFloat(0.2f, 0.5f); //fromWeight, toWeight
m1.setDuration(400);
m1.setStartDelay(100); //Optional Delay
m1.setInterpolator(new LinearInterpolator());
m1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
((LinearLayout.LayoutParams) viewToAnimate.getLayoutParams()).weight = (float) animation.getAnimatedValue();
viewToAnimate.requestLayout();
}
});
m1.start();
More About ValueAnimator
Another way is to use old Animation class, as described in https://stackoverflow.com/a/20334557/2914140. In this case you can simultaneously change weights of several Views.
private static class ExpandAnimation extends Animation {
private final View[] views;
private final float startWeight;
private final float deltaWeight;
ExpandAnimation(View[] views, float startWeight, float endWeight) {
this.views = views;
this.startWeight = startWeight;
this.deltaWeight = endWeight - startWeight;
}
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
float weight = startWeight + (deltaWeight * interpolatedTime);
for (View view : views) {
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) view.getLayoutParams();
lp.weight = weight;
view.setLayoutParams(lp);
}
views[0].getParent().requestLayout();
}
#Override
public boolean willChangeBounds() {
return true;
}
}
All of the answers above weren't working for me (they would simply "snap" and not animate), but after I added weight_sum="1" to the parent layout, it started working. Just in case someone else comes up with the same issue.