nhaarman
nhaarman

Reputation: 100358

LayoutTransition: Animate View next to an expanding View

I've recreated my problem to a very simple representation. I have 3 TextViews. 2 of them are in a seperate LinearLayout, the third is on the same level as the LinearLayout. I'm toggling the visibility of test1 and test2, and I'd like to see them fade away (which works). Furthermore, I want test3 to slide into his new place (taking place of test1 and test2). I can't make this happen. test3 just snaps to it's new point.

How can I achive this?

My code:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/parent"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:animateLayoutChanges="true"
    android:orientation="vertical" >

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Click" />

    <LinearLayout android:animateLayoutChanges="true"
        android:id="@+id/child1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical" >

        <TextView
            android:id="@+id/test1"
            android:layout_width="match_parent" android:visibility="gone"
            android:layout_height="wrap_content"
            android:text="TEST1" />

        <TextView
            android:id="@+id/test2"
            android:layout_width="match_parent" android:visibility="gone"
            android:layout_height="wrap_content"
            android:text="TEST2" />
    </LinearLayout>

    <TextView
        android:id="@+id/test3"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="TEST3" />

</LinearLayout>

And in my Activity:

public class LayoutAnimations extends Activity {
    private boolean toggle = true;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.layout_animations);

        Button button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                if (toggle) {
                    findViewById(R.id.test1).setVisibility(View.VISIBLE);
                    findViewById(R.id.test2).setVisibility(View.VISIBLE);
                } else {
                    findViewById(R.id.test1).setVisibility(View.GONE);
                    findViewById(R.id.test2).setVisibility(View.GONE);
                }
                toggle = !toggle;
            }
        });

    }

}

Edit: I actually have another TextView next to test1 and test2 which should be visible at all times, so I can't just hide the LinearLayout itself.

Upvotes: 14

Views: 28753

Answers (4)

Gaurav Arora
Gaurav Arora

Reputation: 17264

I wanted the same thing to happen in my app. To achieve this:

  1. Create a suitable animation in Res/anim. I've used a slide out from left kind of animation. You can google other if you aren't satisfied with this one.

    slide_out_left.xml

    <translate
        android:duration="@android:integer/config_mediumAnimTime"
        android:fromXDelta="0"
        android:toXDelta="-50%p" />
    
    <alpha
        android:duration="@android:integer/config_mediumAnimTime"
        android:fromAlpha="1.0"
        android:toAlpha="0.0" />
    

  2. Attach animation defined above with view you want to animate, (in your case child1 containing text1 and text2)

    Animation outAnimation;
    LinearLayout a1 = (LinearLayout)findViewById(R.id.child1); 
    
    outAnimation = (Animation) AnimationUtils.loadAnimation (getApplicationContext(), R.anim.slide_out_left);
    
    a1.setAnimation(outAnimation);
    outAnimation.setAnimationListener(new  AnimationListener() {
    
        @Override
        public void onAnimationEnd(Animation arg0) {
        a1.setVisibility(View.GONE);                            
        }
        @Override
        public void onAnimationRepeat(Animation animation) {
            // TODO Auto-generated method stub                          
        }
    
        @Override
        public void onAnimationStart(Animation animation) {
            // TODO Auto-generated method stub
        }                 
    });
    a1.startAnimation(outAnimation);
    

NOTE: I've attached animation with child1 instead of text3 because when child1 will slide out slowly it will automatically give an illusion that text3 is sliding in.

Upvotes: 5

nhaarman
nhaarman

Reputation: 100358

I've solved it using an other question. See this answer

Quoting:

I believe the simplest approach is to extend Animation class and override applyTransformation() to change the view's height as follows:

import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.view.animation.Animation;
import android.view.animation.Transformation;
import android.widget.LinearLayout;

public class MyCustomAnimation extends Animation {

    public final static int COLLAPSE = 1;
    public final static int EXPAND = 0;

    private View mView;
    private int mEndHeight;
    private int mType;
    private LinearLayout.LayoutParams mLayoutParams;

    public MyCustomAnimation(View view, int duration, int type) {

        setDuration(duration);
        mView = view;
        mEndHeight = mView.getHeight();
        mLayoutParams = ((LinearLayout.LayoutParams) view.getLayoutParams());
        mType = type;
        if(mType == EXPAND) {
            mLayoutParams.height = 0;
        } else {
            mLayoutParams.height = LayoutParams.WRAP_CONTENT;
        }
        view.setVisibility(View.VISIBLE);
    }

    public int getHeight(){
        return mView.getHeight();
    }

    public void setHeight(int height){
        mEndHeight = height;
    }

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {

        super.applyTransformation(interpolatedTime, t);
        if (interpolatedTime < 1.0f) {
            if(mType == EXPAND) {
                mLayoutParams.height =  (int)(mEndHeight * interpolatedTime);
            } else {
                mLayoutParams.height = (int) (mEndHeight * (1 - interpolatedTime));
            }
            mView.requestLayout();
        } else {
            if(mType == EXPAND) {
                mLayoutParams.height = LayoutParams.WRAP_CONTENT;
                mView.requestLayout();
            }else{
                mView.setVisibility(View.GONE);
            }
        }
    }
}

To use it, set your onclick() as follows:

int height;

@Override
public void onClick(View v) {
    if(view2.getVisibility() == View.VISIBLE){
        MyCustomAnimation a = new MyCustomAnimation(view2, 1000, MyAnimation.COLLAPSE);
        height = a.getHeight();
        view2.startAnimation(a);
    }else{
        MyCustomAnimation a = new MyCustomAnimation(view2, 1000, MyAnimation.EXPAND);
        a.setHeight(height);
        view2.startAnimation(a);
    }
}

Regards.

Upvotes: 8

Sanket Kachhela
Sanket Kachhela

Reputation: 10856

use this animation XML slide_in_left.XML

<translate
    android:duration="500"
    android:fromXDelta="-100%"
    android:fromYDelta="0%"
    android:toXDelta="0%"
    android:toYDelta="0%" />
</set>

and slid_in_right.XML

<translate
    android:duration="500"
    android:fromXDelta="100%"
    android:fromYDelta="0%"
    android:toXDelta="0%"
    android:toYDelta="0%" />
</set>

use this animation Animation slideinleft,slideinright;

and initlize this animation

public void AnimationInitialization() {

    slideinleft= AnimationUtils
            .loadAnimation(this, R.anim.slide_in_left);


    slideinright= AnimationUtils.loadAnimation(this,
            R.anim.slide_in_right);

}

and call this 2 function for changing visibilty

public void showMenu() {

    linearlayout_first.clearAnimation();

    linearlayout_first.startAnimation(slideinleft);

    linearlayout_first.setVisibility(View.VISIBLE);

}

public void hideMenu() {

    linearlayout_second.clearAnimation();
    linearlayout_second.startAnimation(slideinright);


    linearlayout_second.setVisibility(View.GONE);
}

you can change layout as you require. also change in Xdelta and Ydelta of animation XML..

Upvotes: 2

Ron
Ron

Reputation: 24233

The documentation is bit confusing. For android:animateLayoutChanges, it says

... When this flag is set to true, a default LayoutTransition object will be set on the ViewGroup container and default animations will run when these layout changes occur.

while the documentation of setLayoutTransition method of ViewGroup class says :

By default, the transition object is null (so layout changes are not animated).

You should try setting a LayoutTransition on the layout.

Here is an example that does that.. http://www.java2s.com/Code/Android/UI/UseLayoutTransitiontoautomatetransitionanimationsasitemsarehiddenorshowninacontainer.htm

Upvotes: 1

Related Questions