384

I have a LinearLayout that I want to show or hide with an Animation that pushes the layout upwards or downwards whenever I change its visibility.

I've seen a few samples out there but none of them suit my needs.

I have created two xml files for the animations but I do not know how to start them when I change the visibility of a LinearLayout.

Xaver Kapeller
  • 49,491
  • 11
  • 98
  • 86
MichelReap
  • 5,630
  • 11
  • 37
  • 99

20 Answers20

724

With the new animation API that was introduced in Android 3.0 (Honeycomb) it is very simple to create such animations.

Sliding a View down by a distance:

view.animate().translationY(distance);

You can later slide the View back to its original position like this:

view.animate().translationY(0);

You can also easily combine multiple animations. The following animation will slide a View down by its height and fade it in at the same time:

// Prepare the View for the animation
view.setVisibility(View.VISIBLE);
view.setAlpha(0.0f);

// Start the animation
view.animate()
    .translationY(view.getHeight())
    .alpha(1.0f)
    .setListener(null);

You can then fade the View back out and slide it back to its original position. We also set an AnimatorListener so we can set the visibility of the View back to GONE once the animation is finished:

view.animate()
    .translationY(0)
    .alpha(0.0f)
    .setListener(new AnimatorListenerAdapter() {
        @Override
        public void onAnimationEnd(Animator animation) {
            super.onAnimationEnd(animation);
            view.setVisibility(View.GONE);
        }
    });
Shahab Rauf
  • 3,651
  • 29
  • 38
Xaver Kapeller
  • 49,491
  • 11
  • 98
  • 86
  • 2
    why view not visible once it gone? – Ram Jun 09 '16 at 08:46
  • @Ram You mean why is a `View` not drawn on the screen when you set its visibility to `View.GONE`? – Xaver Kapeller Jun 09 '16 at 08:47
  • 1
    i want to animate view when visible and when gone. but if i first gone view .it not able to visible and place of view is blank – Ram Jun 09 '16 at 08:58
  • 3
    @Ram What are you trying to achieve by animating a `View` when its visibility is set to `View.GONE`? If you set its visibility to anything besides `View.VISIBLE` then the `View` will not be visible. I don't understand what you are asking. If you want your animation to be visible then don't set the visibility of the `View` to `View.GONE`. – Xaver Kapeller Jun 09 '16 at 09:11
  • thanks it work when i removed view.setVisibility(View.GONE); – Ram Jun 09 '16 at 10:08
  • @Xaver, same issue here not working even after removing view.SetVisibility(View.GONE) – Pankaj kumar Aug 08 '16 at 10:23
  • @PKR what kind of answer do you expect from me now? You are doing something wrong. But without having even the slightest bit of information I can't help you. – Xaver Kapeller Aug 08 '16 at 10:25
  • 2
    facing same issue what Ram was facing, at first time it works fine but from next time when i make that view in gone state and try to make that view visible again it doesn't appear. – Pankaj kumar Aug 08 '16 at 10:35
  • @PKR Just ask a question. Include all the relevant code and describe the exact problem and what you have tried so far. If you do that you will surely get a proper answer. – Xaver Kapeller Aug 08 '16 at 10:45
  • 13
    @XaverKapeller I think the problem many have is that the listener `onAnimationEnd` is called every time for a multi-occurring animation, which means that `onAnimationEnd` is called also when the view get shown, which sets its visibility to Gone, etc. – oldergod Sep 20 '16 at 03:00
  • 1
    How do I solve the issue of not being visible again on 2nd time? – Vincent Paing Feb 15 '17 at 17:24
  • @Vincent_Paing What are you talking about? – Xaver Kapeller Feb 16 '17 at 04:38
  • View is visible once, and then on next time after it's have been animated to gone. It's not visible only for a short time, I've tried setListener(null) to remove existing listeners but it doesn't work either – Vincent Paing Feb 17 '17 at 12:27
  • @Vincent_Paing Are you setting the `View` to `View.VISIBLE` again? – Xaver Kapeller Feb 17 '17 at 13:19
  • Yes, set VISIBLE and then play the slide in animation again cause it to become GONE – Vincent Paing Feb 18 '17 at 13:58
  • Great answer. How would one combine this with ScrollView? So that when panel moves beyond boundaries, I could scroll down ? Thanx. – Sermilion Feb 18 '17 at 15:52
  • 1
    @Sermilion You are probably going to find your answer by googling around a bit, otherwise ask a new question. But if you ask a new question don't forget to show what you tried so far... – Xaver Kapeller Feb 18 '17 at 16:26
  • I figured it. I set a view below with height that of sliding view and set its visibility to "gone". When I animate, I make visibility visible and ScrollViw takes care of the rest. Seems like a hack but it works as needed) – Sermilion Feb 18 '17 at 16:29
  • 1
    `setListener(null)` when you want to make it visible again after once it gets gone. – Shahab Rauf Aug 03 '17 at 12:28
  • To everyone that are stuck with the issue of the view not being visible after it's gone, @XaverKapeller 's animation sets the view's `alpha` of zero, you must set the `alpha` and the `translation` of the view back to 1 and 0 respectively after the GONE animation in order to show the view afterwards. – Roman Rozenshtein Mar 21 '19 at 20:57
  • 1
    answer should be structured so anyone use answer as method directly without any doubt. – Anand Savjani Apr 05 '19 at 17:50
  • 1
    For people who had a problem getting the view to show after the first time, if your show/hide view is initialized in the hide position, when you do the first animation, `view.getHeight()` will return 0 since the view is GONE. To fix this, change the show Y translation from `view.getHeight()` to 0, and the hide Y translation from 0 to -1 * `view.getHeight()`. – Will Nasby Jul 30 '19 at 21:06
186

I was having troubles understanding an applying the accepted answer. I needed a little more context. Now that I have figured it out, here is a full example:

enter image description here

MainActivity.java

public class MainActivity extends AppCompatActivity {

    Button myButton;
    View myView;
    boolean isUp;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        myView = findViewById(R.id.my_view);
        myButton = findViewById(R.id.my_button);

        // initialize as invisible (could also do in xml)
        myView.setVisibility(View.INVISIBLE);
        myButton.setText("Slide up");
        isUp = false;
    }

    // slide the view from below itself to the current position
    public void slideUp(View view){
        view.setVisibility(View.VISIBLE);
        TranslateAnimation animate = new TranslateAnimation(
                0,                 // fromXDelta
                0,                 // toXDelta
                view.getHeight(),  // fromYDelta
                0);                // toYDelta
        animate.setDuration(500);
        animate.setFillAfter(true);
        view.startAnimation(animate);
    }

    // slide the view from its current position to below itself
    public void slideDown(View view){
        TranslateAnimation animate = new TranslateAnimation(
                0,                 // fromXDelta
                0,                 // toXDelta
                0,                 // fromYDelta
                view.getHeight()); // toYDelta
        animate.setDuration(500);
        animate.setFillAfter(true);
        view.startAnimation(animate);
    }

    public void onSlideViewButtonClick(View view) {
        if (isUp) {
            slideDown(myView);
            myButton.setText("Slide up");
        } else {
            slideUp(myView);
            myButton.setText("Slide down");
        }
        isUp = !isUp;
    }
}

activity_mail.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.slideview.MainActivity">

    <Button
        android:id="@+id/my_button"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="100dp"
        android:onClick="onSlideViewButtonClick"
        android:layout_width="150dp"
        android:layout_height="wrap_content"/>

    <LinearLayout
        android:id="@+id/my_view"
        android:background="#a6e1aa"
        android:orientation="vertical"
        android:layout_alignParentBottom="true"
        android:layout_width="match_parent"
        android:layout_height="200dp">

    </LinearLayout>

</RelativeLayout>

Notes

  • Thanks to this article for pointing me in the right direction. It was more helpful than the other answers on this page.
  • If you want to start with the view on screen, then don't initialize it as INVISIBLE.
  • Since we are animating it completely off screen, there is no need to set it back to INVISIBLE. If you are not animating completely off screen, though, then you can add an alpha animation and set the visibility with an AnimatorListenerAdapter.
  • Property Animation docs
Suragch
  • 484,302
  • 314
  • 1,365
  • 1,393
  • android:visibility="invisible" to initialise the view animation as a hide – Goodlife Jan 21 '18 at 06:13
  • 7
    I don't recommend use of animate.setFillAfter(true); if you have clickable views under the slided view it will not recive events – HOCiNE BEKKOUCHE Mar 24 '18 at 17:40
  • 2
    Notice that without `.setVisibility(View.INVISIBLE);` the slide up function won't work as visually expected. – Advait Saravade Aug 03 '18 at 03:57
  • `Translate Animation` moves the view. If you want to animate view like its scaling itself then use `ScaleAnimation anim = new ScaleAnimation(1, 1, 0, 1)` – Zohab Ali Sep 29 '18 at 09:05
  • Note that `TranslateAnimation` won't move clickables if they are present in your view. It will just move pixels. This can be unexpected in most cases. Refer this to move clickables as well: https://stackoverflow.com/a/34631361/5353128 – Kaushal28 May 20 '21 at 18:12
95

Now visibility change animations should be done via Transition API which available in support (androidx) package. Just call TransitionManager.beginDelayedTransition method with Slide transition then change visibility of the view.

enter image description here

import androidx.transition.Slide;
import androidx.transition.Transition;
import androidx.transition.TransitionManager;

private void toggle(boolean show) {
    View redLayout = findViewById(R.id.redLayout);
    ViewGroup parent = findViewById(R.id.parent);

    Transition transition = new Slide(Gravity.BOTTOM);
    transition.setDuration(600);
    transition.addTarget(R.id.redLayout);

    TransitionManager.beginDelayedTransition(parent, transition);
    redLayout.setVisibility(show ? View.VISIBLE : View.GONE);
}

activity_main.xml

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

    <Button
        android:id="@+id/btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="play" />

    <LinearLayout
        android:id="@+id/redLayout"
        android:layout_width="match_parent"
        android:layout_height="400dp"
        android:background="#5f00"
        android:layout_alignParentBottom="true" />
</RelativeLayout>

Check this answer with another default and custom transition examples.

Aba
  • 2,307
  • 2
  • 18
  • 32
ashakirov
  • 12,112
  • 6
  • 40
  • 40
52

Easiest solution: set android:animateLayoutChanges="true" on the container holding your views.

To put it into some context: If you have a layout like below, all visibility changes to the views in this container will be animated automatically.

<LinearLayout android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:animateLayoutChanges="true"
    >

    <Views_which_change_visibility>

</LinearLayout>

You can find more details about this on Animating Layout Changes - Android Developer

Stefan Medack
  • 2,731
  • 26
  • 32
  • It is the easiest but it's behavior differs due to phone manufacturer and he's code changes – b2mob Aug 18 '17 at 12:15
  • This animates the alpha, not the position. – Suragch Oct 10 '17 at 03:30
  • Yes, but that's what the original question was about if I understood it correctly. If you want to animate positions, you could use a RecyclerView that uses ViewHolders with stable ids. – Stefan Medack Oct 12 '17 at 18:32
  • in case it didn't work in nested views refer to this answer https://stackoverflow.com/a/59649918/6039240 – Amr Jul 28 '21 at 06:23
23

Kotlin

Based on Suragch's answer, here is an elegant way using View extension:

fun View.slideUp(duration: Int = 500) {
    visibility = View.VISIBLE
    val animate = TranslateAnimation(0f, 0f, this.height.toFloat(), 0f)
    animate.duration = duration.toLong()
    animate.fillAfter = true
    this.startAnimation(animate)
}

fun View.slideDown(duration: Int = 500) {
    visibility = View.VISIBLE
    val animate = TranslateAnimation(0f, 0f, 0f, this.height.toFloat())
    animate.duration = duration.toLong()
    animate.fillAfter = true
    this.startAnimation(animate)
}

And then wherever you want to use it, you just need myView.slideUp() or myView.slideDown()

Đorđe Nilović
  • 3,600
  • 1
  • 25
  • 20
  • Only bug is, it doesn't need "fillAfter=true" as it block child views click accessibility – Ranjan Jul 11 '19 at 07:04
  • Also You would probably need to add a listener to slideDown animation and make view gone onAnimationEnd. – Manohar Jun 12 '20 at 13:31
12

You can start the correct Animation when the visibility of the LinearLayout changes by creating a new subclass of LinearLayout and overriding setVisibility() to start the Animations. Consider something like this:

public class SimpleViewAnimator extends LinearLayout
{
    private Animation inAnimation;
    private Animation outAnimation;

    public SimpleViewAnimator(Context context)
    {
        super(context);
    }

    public void setInAnimation(Animation inAnimation)
    {
        this.inAnimation = inAnimation;
    }

    public void setOutAnimation(Animation outAnimation)
    {
        this.outAnimation = outAnimation;
    }

    @Override
    public void setVisibility(int visibility)
    {
        if (getVisibility() != visibility)
        {
            if (visibility == VISIBLE)
            {
                if (inAnimation != null) startAnimation(inAnimation);
            }
            else if ((visibility == INVISIBLE) || (visibility == GONE))
            {
                if (outAnimation != null) startAnimation(outAnimation);
            }
        }

        super.setVisibility(visibility);
    }
}
Xaver Kapeller
  • 49,491
  • 11
  • 98
  • 86
  • 1
    I actually like better the subclass approach. Thank you very much. – MichelReap Nov 04 '13 at 11:08
  • 1
    This, is an awesome solution that I'm gonna implement in my BaseView. Thx for this! – Bram Vandenbussche Jul 04 '14 at 13:50
  • 1
    As this works when showing, when hiding, the view disappears before the animation can be seen. Any workarounds? – Bernardo Nov 27 '14 at 16:10
  • 12
    @BramVandenbussche This is a terrible solution. It makes the `View` responsible for its own animations which is **NEVER** what you want. Imagine you want to animate the `View` differently in another part of your app. What do you do then? Add a flag to not automatically animate the visibility? Subclass the `View` and override `setVisibility()` to remove the animation? Or even worse implement `setVisibility()` with another animation? It just gets uglier and uglier from there. Don't use this "solution". – Xaver Kapeller Jan 26 '15 at 11:16
  • 3
    Better call it AnimatedLinearLayout – Roel Feb 10 '15 at 10:48
  • This is really nice. The way I had my layout set up already was just toggling visible/invisible, and this is the easiest way to add animation without changing too much. – AdamMc331 May 06 '15 at 03:13
  • 1
    @McAdam331 No. The easiest way to add animation is just to add the `android:animateLayoutChanges="true"` attribute to your layout xml and then android will animate your appearing and disappearing `Views` automatically. – Xaver Kapeller Nov 05 '15 at 10:15
9
if (filter_section.getVisibility() == View.GONE) {
    filter_section.animate()
            .translationY(filter_section.getHeight()).alpha(1.0f)
            .setListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationStart(Animator animation) {
                    super.onAnimationStart(animation);
                    filter_section.setVisibility(View.VISIBLE);
                    filter_section.setAlpha(0.0f);
                }
            });
} else {
    filter_section.animate()
            .translationY(0).alpha(0.0f)
            .setListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    super.onAnimationEnd(animation);
                    filter_section.setVisibility(View.GONE);
                }
            });
}
Xaver Kapeller
  • 49,491
  • 11
  • 98
  • 86
Ameen Maheen
  • 2,719
  • 1
  • 28
  • 28
  • 11
    Issues with this answer: 1) Terrible code formatting. 2) You use a code snippet to post code which actually cannot be run in the browser. This doesn't just add two useless buttons, but it also destroys syntax highlighting. 3) It's just some random code dump without any explanation or purpose. 4) You are changing the visibility while performing an animation. Aside from the fact that this is obvious code smell this will also not work properly. Changing visibility starts a new layouting process, only after that is finished the animation actually has values to work with. The list goes on and on... – Xaver Kapeller Apr 01 '15 at 06:57
  • I have already edited your answer to fix formatting and turned the code snippet into an actual code block. But you have to fill in the rest... – Xaver Kapeller Apr 01 '15 at 07:11
  • Sorry got it mate, i made up the code from yours because it doesn't work well for me ,this code of mine works.but changes needed in the way of posting i agree . – Ameen Maheen Apr 01 '15 at 09:13
  • @AmeenMaheen What is `setAlpha` for? – IgorGanapolsky Sep 14 '15 at 19:46
  • @ Igor Ganapolsky it is used for transparency ie to give a fading effect – Ameen Maheen Sep 15 '15 at 04:55
7

you can slide up and down any view or layout by using bellow code in android app

boolean isClicked = false;
LinearLayout mLayoutTab = (LinearLayout) findViewById(R.id.linearlayout);

if(isClicked) {
    isClicked = false;
    mLayoutTab.animate()
        .translationYBy(120)
        .translationY(0)     
        .setDuration(getResources().getInteger(android.R.integer.config_mediumAnimTime));
} else {
    isClicked = true;
    mLayoutTab.animate()
         .translationYBy(0)
         .translationY(120)
         .setDuration(getResources().getInteger(android.R.integer.config_mediumAnimTime));
}
Michael
  • 113
  • 3
  • 13
varotariya vajsi
  • 3,965
  • 37
  • 39
  • what is 120? and what is 0? what's the unit for setDuration if I want to hardcode this? – stanley santoso Aug 29 '15 at 16:14
  • 1
    here 120 and 0 is the distance related to Y axis if you put hard code than getting problem in large screen or tablet so, you need to put value from your string.xml value for all the different device. and duration is the time you want to show animation of layout....!!! sorry for my poor English...! – varotariya vajsi Sep 08 '15 at 04:02
  • @varotariyavajsi This doesn't actually show/hide the visibility of a view. – IgorGanapolsky Sep 14 '15 at 19:43
  • hello igor ganapolsky i know these...it is just translate view in y direction, if user need to show up and down like a bottom slider it will be working fine. – varotariya vajsi Sep 15 '15 at 06:39
6

Using ObjectAnimator

private fun slideDown(view: View) {
    val height = view.height
    ObjectAnimator.ofFloat(view, View.TRANSLATION_Y, 0f, height.toFloat()).apply {
        duration = 1000
        start()
    }
}

private fun slideUp(view: View) {
    val height = view.height
    ObjectAnimator.ofFloat(view, View.TRANSLATION_Y, height.toFloat(), 0f)).apply {
        duration = 1000
        start()
    }
}
Boken
  • 4,825
  • 10
  • 32
  • 42
Vihaan Verma
  • 12,815
  • 19
  • 97
  • 126
  • 4
    Minor improvments: We can use constant View.TRANSLATION_Y instead of "translationY" and also in the slide up ObjectAnimation we can do .apply { doOnEnd { view.visibility = View.GONE } .......}.start() – tashi Mar 27 '20 at 20:16
  • `0.toFloat()` can also just be `0f` – Tyler May 04 '20 at 14:51
4

Use this class:

public class ExpandCollapseExtention {

 public static void expand(View view) {
    view.setVisibility(View.VISIBLE);

    final int widthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
    final int heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
    view.measure(widthSpec, heightSpec);

    ValueAnimator mAnimator = slideAnimator(view, 0, view.getMeasuredHeight());
    mAnimator.start();
}


public static void collapse(final View view) {
    int finalHeight = view.getHeight();

    ValueAnimator mAnimator = slideAnimator(view, finalHeight, 0);

    mAnimator.addListener(new Animator.AnimatorListener() {

        @Override
        public void onAnimationEnd(Animator animator) {               
            view.setVisibility(View.GONE);
        }


        @Override
        public void onAnimationStart(Animator animation) {

        }


        @Override
        public void onAnimationCancel(Animator animation) {

        }


        @Override
        public void onAnimationRepeat(Animator animation) {

        }
    });
    mAnimator.start();
}


private static ValueAnimator slideAnimator(final View v, int start, int end) {

    ValueAnimator animator = ValueAnimator.ofInt(start, end);

    animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

        @Override
        public void onAnimationUpdate(ValueAnimator valueAnimator) {

            int value = (Integer) valueAnimator.getAnimatedValue();
            ViewGroup.LayoutParams layoutParams = v.getLayoutParams();
            layoutParams.height = value;
            v.setLayoutParams(layoutParams);
        }
    });
    return animator;
}
}
amin
  • 561
  • 6
  • 18
4

I had a corner case where my view's height was still zero so...

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.view.View;

public final class AnimationUtils {

  public static void slideDown(final View view) {
        view.animate()
                .translationY(view.getHeight())
                .alpha(0.f)
                .setListener(new AnimatorListenerAdapter() {
                    @Override
                    public void onAnimationEnd(Animator animation) {
                        // superfluous restoration
                        view.setVisibility(View.GONE);
                        view.setAlpha(1.f);
                        view.setTranslationY(0.f);
                    }
                });
    }

    public static void slideUp(final View view) {
        view.setVisibility(View.VISIBLE);
        view.setAlpha(0.f);

        if (view.getHeight() > 0) {
            slideUpNow(view);
        } else {
            // wait till height is measured
            view.post(new Runnable() {
                @Override
                public void run() {
                    slideUpNow(view);
                }
            });
        }
    }

    private static void slideUpNow(final View view) {
        view.setTranslationY(view.getHeight());
        view.animate()
                .translationY(0)
                .alpha(1.f)
                .setListener(new AnimatorListenerAdapter() {
                    @Override
                    public void onAnimationEnd(Animator animation) {
                        view.setVisibility(View.VISIBLE);
                        view.setAlpha(1.f);
                    }
                });
    }

}
Samuel
  • 9,883
  • 5
  • 45
  • 57
4

With Kotlin extensions you can use this:

enum class SlideDirection{
    UP,
    DOWN,
    LEFT,
    RIGHT
}

enum class SlideType{
    SHOW,
    HIDE
}

fun View.slideAnimation(direction: SlideDirection, type: SlideType, duration: Long = 250){
    val fromX: Float
    val toX: Float
    val fromY: Float
    val toY: Float
    val array = IntArray(2)
    getLocationInWindow(array)
    if((type == SlideType.HIDE && (direction == SlideDirection.RIGHT || direction == SlideDirection.DOWN)) ||
        (type == SlideType.SHOW && (direction == SlideDirection.LEFT || direction == SlideDirection.UP))   ){
        val displayMetrics = DisplayMetrics()
        val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
        windowManager.defaultDisplay.getMetrics(displayMetrics)
        val deviceWidth = displayMetrics.widthPixels
        val deviceHeight = displayMetrics.heightPixels
        array[0] = deviceWidth
        array[1] = deviceHeight
    }
    when (direction) {
        SlideDirection.UP -> {
            fromX = 0f
            toX = 0f
            fromY = if(type == SlideType.HIDE) 0f else (array[1] + height).toFloat()
            toY = if(type == SlideType.HIDE) -1f * (array[1] + height)  else 0f
        }
        SlideDirection.DOWN -> {
            fromX = 0f
            toX = 0f
            fromY = if(type == SlideType.HIDE) 0f else -1f * (array[1] + height)
            toY = if(type == SlideType.HIDE) 1f * (array[1] + height)  else 0f
        }
        SlideDirection.LEFT -> {
            fromX = if(type == SlideType.HIDE) 0f else 1f * (array[0] + width)
            toX = if(type == SlideType.HIDE) -1f * (array[0] + width) else 0f
            fromY = 0f
            toY = 0f
        }
        SlideDirection.RIGHT -> {
            fromX = if(type == SlideType.HIDE) 0f else -1f * (array[0] + width)
            toX = if(type == SlideType.HIDE) 1f * (array[0] + width) else 0f
            fromY = 0f
            toY = 0f
        }
    }
    val animate = TranslateAnimation(
        fromX,
        toX,
        fromY,
        toY
    )
    animate.duration = duration
    animate.setAnimationListener(object: Animation.AnimationListener{
        override fun onAnimationRepeat(animation: Animation?) {

        }

        override fun onAnimationEnd(animation: Animation?) {
            if(type == SlideType.HIDE){
                visibility = View.INVISIBLE
            }
        }

        override fun onAnimationStart(animation: Animation?) {
            visibility = View.VISIBLE
        }

    })
    startAnimation(animate)
}

Example for the extension:

view.slideAnimation(SlideDirection.UP, SlideType.HIDE)//to make it disappear through top of the screen
view.slideAnimation(SlideDirection.DOWN, SlideType.SHOW)//to make it reappear from top of the screen

view.slideAnimation(SlideDirection.DOWN, SlideType.HIDE)//to make it disappear through bottom of the screen
view.slideAnimation(SlideDirection.UP, SlideType.SHOW)//to make it reappear from bottom of the screen
Mertcan Çüçen
  • 466
  • 3
  • 13
3

You can used the simple three lines of code to show the animation...

//getting the hiding view by animation

 mbinding.butn.setOnClickListener {

                val SlideOutLeft = AnimationUtils.loadAnimation(this, R.anim.slide_out_left)
                simplelayout.visibility = View.INVISIBLE
                simplelayout.startAnimation(SlideOutLeft)


                val SlideInRight = AnimationUtils.loadAnimation(applicationContext, R.anim.slide_in_right)
                animation1.visibility = View.VISIBLE
                animation1.startAnimation(SlideInRight)

            }
            //again unhide the view animation
            mbinding.buttn.setOnClickListener {


               val SlideInLeft=AnimationUtils.loadAnimation(this,R.anim.slide_in_left)
                //set the layout
               simplelayout.visibility=View.VISIBLE
               simplelayout.startAnimation(SlideInLeft)

               val SlideOutRight=AnimationUtils.loadAnimation(this,R.anim.slide_out_right)
               animation1.visibility=View.INVISIBLE
               animation1.startAnimation(SlideOutRight)

            }
Jay Thakkar
  • 1,392
  • 10
  • 19
2

One of the simple ways:

containerView.setLayoutTransition(LayoutTransition())
containerView.layoutTransition.enableTransitionType(LayoutTransition.CHANGING)
hallz12
  • 629
  • 2
  • 9
  • 15
2

If you want to show/hide many views together with Transition, you can can use TransitionSet (because you can not play 2 "single" Transition together)

fun slideTopBottomVisibility(topLayout: View, bottomLayout: View, show: Boolean) {
    val topTransition: Transition = Slide(Gravity.TOP)
    topTransition.duration = 600
    topTransition.addTarget(topLayout)

    val bottomTransition: Transition = Slide(Gravity.BOTTOM)
    bottomTransition.duration = 600
    bottomTransition.addTarget(bottomLayout)

    val transitionSet = TransitionSet()
    transitionSet.addTransition(topTransition)
    transitionSet.addTransition(bottomTransition)

    TransitionManager.beginDelayedTransition(topLayout.parent as ViewGroup, transitionSet)
    topLayout.visibility = if (show) View.VISIBLE else View.GONE
    bottomLayout.visibility = if (show) View.VISIBLE else View.GONE
}
Linh
  • 57,942
  • 23
  • 262
  • 279
1

Here is my solution. Just get a reference to your view and call this method:

public static void animateViewFromBottomToTop(final View view){

    view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {

        @Override
        public void onGlobalLayout() {

            view.getViewTreeObserver().removeOnGlobalLayoutListener(this);

            final int TRANSLATION_Y = view.getHeight();
            view.setTranslationY(TRANSLATION_Y);
            view.setVisibility(View.GONE);
            view.animate()
                .translationYBy(-TRANSLATION_Y)
                .setDuration(500)
                .setStartDelay(200)
                .setListener(new AnimatorListenerAdapter() {

                    @Override
                    public void onAnimationStart(final Animator animation) {

                        view.setVisibility(View.VISIBLE);
                    }
                })
                .start();
        }
    });
}

No need to do anything else =)

  • 1
    Why would you need a GlobalLayoutListener to do this? Why are you setting the visibility on such a weird way? Why are you including things like a start delay which is irrelevant to question in your answer? – Xaver Kapeller Nov 11 '16 at 14:08
1

Suragch's answer in Kotlin. This worked for me.

class MainActivity : AppCompatActivity() {

var isUp: Boolean = false

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    var myView: View = findViewById(R.id.my_view)
    var myButton: Button = findViewById(R.id.my_button)

    //Initialize as invisible
    myView.visibility = View.INVISIBLE
    myButton.setText("Slide up")

    isUp = false

}


fun View.slideUp(duration: Int = 500){
    visibility = View.VISIBLE
    val animate = TranslateAnimation(0f, 0f, this.height.toFloat(), 0f)
    animate.duration = duration.toLong()
    animate.fillAfter = true
    this.startAnimation(animate)
}

fun View.slideDown(duration: Int = 500) {
    visibility = View.VISIBLE
    val animate = TranslateAnimation(0f, 0f, 0f, this.height.toFloat())
    animate.duration = duration.toLong()
    animate.fillAfter = true
    this.startAnimation(animate)
}

fun onSlideViewButtonClick(view: View){
    if(isUp){
        my_view.slideDown()
        my_button.setText("Slide Up")

    }
    else{
        my_view.slideUp()
        my_button.setText("Slide Down")
    }
    isUp = !isUp
}

}

olle
  • 134
  • 3
  • 15
1

From the answer of ashakirov for Kotlin user

 val transition: Transition = Slide(Gravity.BOTTOM)
                transition.duration = 600
                transition.addTarget(you_parent_layout_id)
TransitionManager.beginDelayedTransition(rootLayoutId, transition)
                yourViewIdToHide.visibility = if (yourViewIdToHide.isShown) View.GONE else View.VISIBLE
Sniffer
  • 1,495
  • 2
  • 14
  • 30
0

Here's another way to do for multiple Button(In this case ImageView)

MainActivity.java

findViewById(R.id.arrowIV).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                if (strokeWidthIV.getAlpha() == 0f) {
                    findViewById(R.id.arrowIV).animate().rotationBy(180);

                    strokeWidthIV.animate().translationXBy(-120 * 4).alpha(1f);
                    findViewById(R.id.colorChooseIV).animate().translationXBy(-120 * 3).alpha(1f);
                    findViewById(R.id.saveIV).animate().translationXBy(-120 * 2).alpha(1f);
                    findViewById(R.id.clearAllIV).animate().translationXBy(-120).alpha(1f);
                } else {
                    findViewById(R.id.arrowIV).animate().rotationBy(180);

                    strokeWidthIV.animate().translationXBy(120 * 4).alpha(0f);
                    findViewById(R.id.colorChooseIV).animate().translationXBy(120 * 3).alpha(0f);
                    findViewById(R.id.saveIV).animate().translationXBy(120 * 2).alpha(0f);
                    findViewById(R.id.clearAllIV).animate().translationXBy(120).alpha(0f);
                }
            }
        });

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:app="http://schemas.android.com/apk/res-auto"
 xmlns:tools="http://schemas.android.com/tools"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 tools:context=".activity.MainActivity">

 <ImageView
     android:id="@+id/strokeWidthIV"
     android:layout_width="48dp"
     android:layout_height="48dp"
     android:layout_margin="8dp"
     android:alpha="0"
     android:contentDescription="Clear All"
     android:padding="4dp"
     android:scaleType="fitXY"
     android:src="@drawable/ic_edit"
     app:layout_constraintEnd_toEndOf="parent"
     app:layout_constraintTop_toTopOf="parent"
     tools:ignore="HardcodedText" />

 <ImageView
     android:id="@+id/colorChooseIV"
     android:layout_width="48dp"
     android:layout_height="48dp"
     android:layout_margin="8dp"
     android:alpha="0"
     android:contentDescription="Clear All"
     android:padding="4dp"
     android:scaleType="fitXY"
     android:src="@drawable/ic_palette"
     app:layout_constraintEnd_toEndOf="parent"
     app:layout_constraintTop_toTopOf="parent"
     tools:ignore="HardcodedText" />

 <ImageView
     android:id="@+id/saveIV"
     android:layout_width="48dp"
     android:layout_height="48dp"
     android:layout_margin="8dp"
     android:alpha="0"
     android:contentDescription="Clear All"
     android:padding="4dp"
     android:scaleType="fitXY"
     android:src="@drawable/ic_save"
     app:layout_constraintEnd_toEndOf="parent"
     app:layout_constraintTop_toTopOf="parent"
     tools:ignore="HardcodedText" />

 <ImageView
     android:id="@+id/clearAllIV"
     android:layout_width="48dp"
     android:layout_height="48dp"
     android:layout_margin="8dp"
     android:alpha="0"
     android:contentDescription="Clear All"
     android:padding="4dp"
     android:scaleType="fitXY"
     android:src="@drawable/ic_clear_all"
     app:layout_constraintEnd_toEndOf="parent"
     app:layout_constraintTop_toTopOf="parent"
     tools:ignore="HardcodedText" />

 <ImageView
     android:id="@+id/arrowIV"
     android:layout_width="48dp"
     android:layout_height="48dp"
     android:layout_margin="8dp"
     android:contentDescription="Arrow"
     android:padding="4dp"
     android:scaleType="fitXY"
     android:src="@drawable/ic_arrow"
     app:layout_constraintEnd_toEndOf="parent"
     app:layout_constraintTop_toTopOf="parent"
     tools:ignore="HardcodedText" />
</androidx.constraintlayout.widget.ConstraintLayout>
Vishnu
  • 663
  • 3
  • 7
  • 24
0

A complete answer which toggles the view visibility in onClick, also flips arrow upside down, and also moves other views up smoothly when hiding the component.

private fun toggleRecyclerViewVisibility(
    recyclerView: RecyclerView,
    container: FrameLayout,
    arrow: ImageView
) {
    //toggle arrow direction, also block user clicks until animation finishes.
    arrow
        .animate()
        .rotation(
            if (arrow.rotation == 0F)
                180F
            else 0F
        )
        .withStartAction { container.isClickable = false }
        .withEndAction { container.isClickable = true }
        .start()

    //toggle recyclerview visibility with animation.
    with(recyclerView) {
        var cof = -1
        var vis = View.GONE
        var alph = 0F

        if (visibility == View.GONE) {
            cof = 0
            vis = View.VISIBLE
            alph = 1F
        }
        animate()
            .translationY(height.toFloat() * cof)
            .alpha(alph)
            .withStartAction {//in case showing the recyclerview show it at the beginning.
                if (vis == View.VISIBLE)
                    visibility = View.VISIBLE
            }
            .withEndAction {//in case hiding the recyclerview hide it at the end.
                if (vis == View.GONE)
                    visibility = View.GONE
            }
            .start()
    }
}

the views looks like this

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

            <!--other views-->
            <LinearLayout
                android:id="@+id/Container"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical">

                <FrameLayout
                    android:id="@+id/header"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:background="@color/backgroundGray"
                    android:padding="16dp">

                    <TextView
                        android:id="@+id/text_view"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="@string/awaitingConfirmation"
                        android:textColor="@color/colorText"
                        android:textSize="16sp" />

                    <ImageView
                        android:id="@+id/arrow_image_view"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_gravity="end|center"
                        android:src="@drawable/ic_arrow" />
                </FrameLayout>

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:orientation="vertical">

                    <androidx.recyclerview.widget.RecyclerView
                        android:id="@+id/recycler"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
                </LinearLayout>
            </LinearLayout>

            <!--other views-->
            </LinearLayout>

then inside your code you add this line first, which solves animateLayoutChanges not working in big nested views, which basically makes other views move up smoothly when hiding the recyclerview

subRootLinearView.layoutTransition.enableTransitionType(LayoutTransition.CHANGING)

also your parent linear layout should include this attribute

android:animateLayoutChanges="true"

then call the method with your views

 toggleRecyclerViewVisibility(
                    recycler,
                    header,
                    arrowImageView
                )
Amr
  • 1,068
  • 12
  • 21