Anyway to programmatically animate layout weight property of linear layout
Asked Answered
C

5

23

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?

Cardon answered 16/7, 2012 at 14:24 Comment(0)
B
36

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();
Bloem answered 4/12, 2015 at 13:59 Comment(1)
need to add @Keep to ViewWeightAnimationWrapper.setWeight method, otherwise there is a warning in Android Studio 3.4Talmudist
H
6

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

Hundredfold answered 27/10, 2017 at 17:36 Comment(0)
H
4

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>
Holophytic answered 25/7, 2012 at 16:28 Comment(1)
This approach has one limitation that you can't nicely animate the first screen to 0 weight. You would need a large weightSum to do that but then the animation will be faster.Entellus
K
0

Another way is to use old Animation class, as described in https://mcmap.net/q/591577/-change-the-weight-of-layout-with-an-animation. 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;
    }
}
Kautz answered 3/10, 2017 at 18:50 Comment(1)
@famfamfam, you can see examples in #18025091, coderwall.com/p/35xi3w/layout-change-animations-sliding-height, gist.github.com/rafali/5146957. But there are more powerful animations now.Kautz
Y
0

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.

Yun answered 2/11, 2018 at 11:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.