Swipe Layout to Hide & Show in Android – Kotlin & Java

In this tutorial, we will discuss how we can swipe layout to hide and show with animation in Android using Kotlin and Java. Below I have shared a utility class that you can add in your project and just call it using 2 lines of code and that’s it. It supports all 4 types of swipes left, right, top & bottom and you can allow only those which are required. By using this utility class we are going to achieve the following type of UI behavior upon swiping with a finger.

Kotlin Code to Swipe Layout to Hide & Show in Android

If you are developing your project in Kotlin create a new class with the name SwipeLayoutToHideAndShow.kt and copy-paste the following code in your class.
For Java code, please scroll down.

package com.handyopinion

import android.view.GestureDetector
import android.view.GestureDetector.SimpleOnGestureListener
import android.view.MotionEvent
import android.view.View
import android.view.View.OnTouchListener
import android.view.ViewGroup
import android.view.animation.Animation
import android.view.animation.TranslateAnimation


class SwipeLayoutToHideAndShow : OnTouchListener {
    enum class SwipeDirection {
        topToBottom, bottomToTop, leftToRight, rightToLeft
    }

    private var rootLayout: ViewGroup? = null
    private var layoutToShowHide: ViewGroup? = null
    private var gestureDetector: GestureDetector? = null
    private var swipeDirections: MutableList<SwipeDirection>? = null

    fun initialize(rootLayout: ViewGroup, layoutToShowHide: ViewGroup?, swipeDirections: MutableList<SwipeDirection>, maxSwipeDistance: Int = 1) {
        val gestureListener = GestureListener()
        gestureDetector = GestureDetector(rootLayout.context, gestureListener)
        this.rootLayout = rootLayout
        this.layoutToShowHide = layoutToShowHide
        this.swipeDirections = swipeDirections
        gestureListener.MAX_SWIPE_DISTANCE = maxSwipeDistance
        this.rootLayout!!.setOnTouchListener(this)
    }

    fun cancel() {
        rootLayout!!.setOnTouchListener(null)
    }

    override fun onTouch(v: View, event: MotionEvent): Boolean {
        return gestureDetector!!.onTouchEvent(event)
    }

    inner class GestureListener : SimpleOnGestureListener() {
        var MAX_SWIPE_DISTANCE = 1
        private val SWIPE_VELOCITY_THRESHOLD = 1

        override fun onDown(e: MotionEvent): Boolean {
            return true
        }

        override fun onFling(e1: MotionEvent, e2: MotionEvent, velocityX: Float, velocityY: Float): Boolean {
            var result = false
            try {
                val diffY = e2.y - e1.y
                val diffX = e2.x - e1.x
                if (Math.abs(diffX) > Math.abs(diffY)) {
                    if (Math.abs(diffX) > MAX_SWIPE_DISTANCE && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
                        if (diffX > 0) {
                            onSwipeLeftToRight()
                        } else {
                            onSwipeRightToLeft()
                        }
                    }
                    result = true
                } else if (Math.abs(diffY) > MAX_SWIPE_DISTANCE && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) {
                    if (diffY > 0) {
                        onSwipeTopToBottom()
                    } else {
                        onSwipeBottomToTop()
                    }
                }
                result = true
            } catch (exception: Exception) {
                exception.printStackTrace()
            }
            return result
        }
    }

    fun onSwipeLeftToRight() {
        val isVisible = layoutToShowHide!!.visibility == View.VISIBLE
        if (swipeDirections!!.contains(SwipeDirection.leftToRight) && isVisible || swipeDirections!!.contains(SwipeDirection.rightToLeft) && !isVisible)
            toggleViewVisibilityWithAnimation(SwipeDirection.leftToRight)
    }

    fun onSwipeRightToLeft() {
        val isVisible =
            layoutToShowHide!!.visibility == View.VISIBLE
        if (swipeDirections!!.contains(SwipeDirection.rightToLeft) && isVisible || swipeDirections!!.contains(SwipeDirection.leftToRight) && !isVisible)
            toggleViewVisibilityWithAnimation(SwipeDirection.rightToLeft)
    }

    fun onSwipeBottomToTop() {
        val isVisible =
            layoutToShowHide!!.visibility == View.VISIBLE
        if (swipeDirections!!.contains(SwipeDirection.bottomToTop) && isVisible || swipeDirections!!.contains(SwipeDirection.topToBottom) && !isVisible)
            toggleViewVisibilityWithAnimation(SwipeDirection.bottomToTop)
    }

    fun onSwipeTopToBottom() {
        val isVisible =
            layoutToShowHide!!.visibility == View.VISIBLE
        if (swipeDirections!!.contains(SwipeDirection.topToBottom) && isVisible || swipeDirections!!.contains(SwipeDirection.bottomToTop) && !isVisible)
            toggleViewVisibilityWithAnimation(SwipeDirection.topToBottom)
    }

    fun toggleViewVisibilityWithAnimation(swipeDirection: SwipeDirection) {
        val currenVisibility = layoutToShowHide!!.visibility
        var deltaVal = if (swipeDirection == SwipeDirection.leftToRight || swipeDirection == SwipeDirection.topToBottom) 1000 else -1000
        if (currenVisibility == View.GONE) {
            deltaVal = -deltaVal
        }
        val fromXDelta = if (currenVisibility == View.VISIBLE || swipeDirection == SwipeDirection.topToBottom || swipeDirection == SwipeDirection.bottomToTop) 0 else deltaVal
        val toXDelta = if (currenVisibility == View.GONE || swipeDirection == SwipeDirection.topToBottom || swipeDirection == SwipeDirection.bottomToTop) 0 else deltaVal
        val fromYDelta = if (currenVisibility == View.VISIBLE || swipeDirection == SwipeDirection.leftToRight || swipeDirection == SwipeDirection.rightToLeft) 0 else deltaVal
        val toYDelta = if (currenVisibility == View.GONE || swipeDirection == SwipeDirection.leftToRight || swipeDirection == SwipeDirection.rightToLeft) 0 else deltaVal
        val animation: Animation = TranslateAnimation(fromXDelta.toFloat(),toXDelta.toFloat(),fromYDelta.toFloat(),toYDelta.toFloat())

        animation.duration = 500
        layoutToShowHide!!.startAnimation(animation)
        layoutToShowHide!!.visibility = if (toXDelta == 0 && toYDelta == 0) View.VISIBLE else View.GONE
    }
}

How to Use this Utility Class in Kotlin

You can add the swipe functionality to any of your layouts in Kotlin by calling the initialize method of the above utility class by adding the following code. The details about the parameters are explained below.

val swipeLayoutToHideAndShow = SwipeLayoutToHideAndShow()
swipeLayoutToHideAndShow.initialize(rootLayout,movingLayout,Arrays.asList(SwipeLayoutToHideAndShow.SwipeDirection.rightToLeft,SwipeLayoutToHideAndShow.SwipeDirection.leftToRight,SwipeLayoutToHideAndShow.SwipeDirection.topToBottom,SwipeLayoutToHideAndShow.SwipeDirection.bottomToTop),50)

Java Code for Swiping Layout to Hide & Show in Android

The following code is the same as above but it’s in Java. So if you are developing your App in Java then create a class in your project with name SwipeLayoutToHideAndShow.java and add the following code in that.

package com.handyopinion;

import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.TranslateAnimation;
import java.util.List;

public class SwipeLayoutToHideAndShow implements View.OnTouchListener {

    public enum SwipeDirection {
        topToBottom, bottomToTop, leftToRight, rightToLeft
    }

    private ViewGroup rootLayout;
    private ViewGroup layoutToShowHide;
    private GestureDetector gestureDetector;
    private List<SwipeDirection> swipeDirections;

    public void initialize(ViewGroup rootLayout, ViewGroup layoutToShowHide, List<SwipeDirection> swipeDirections, int maxSwipeDistance) {
        GestureListener gestureListener = new GestureListener();
        gestureDetector = new GestureDetector(rootLayout.getContext(), gestureListener);
        this.rootLayout = rootLayout;
        this.layoutToShowHide = layoutToShowHide;
        this.swipeDirections = swipeDirections;
        gestureListener.MAX_SWIPE_DISTANCE = maxSwipeDistance;

        this.rootLayout.setOnTouchListener(this);
    }

    public void initialize(ViewGroup rootLayout, ViewGroup layoutToShowHide, List<SwipeDirection> swipeDirections) {
        initialize(rootLayout, layoutToShowHide, swipeDirections, 1);
    }

    public void cancel() {
        rootLayout.setOnTouchListener(null);
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        return gestureDetector.onTouchEvent(event);
    }

    private final class GestureListener extends GestureDetector.SimpleOnGestureListener {

        private int MAX_SWIPE_DISTANCE = 1;
        private final int SWIPE_VELOCITY_THRESHOLD = 1;

        @Override
        public boolean onDown(MotionEvent e) {
            return true;
        }

        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            boolean result = false;
            try {
                float diffY = e2.getY() - e1.getY();
                float diffX = e2.getX() - e1.getX();
                if (Math.abs(diffX) > Math.abs(diffY)) {
                    if (Math.abs(diffX) > MAX_SWIPE_DISTANCE && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
                        if (diffX > 0) {
                            onSwipeLeftToRight();
                        } else {
                            onSwipeRightToLeft();
                        }
                    }
                    result = true;
                } else if (Math.abs(diffY) > MAX_SWIPE_DISTANCE && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) {
                    if (diffY > 0) {
                        onSwipeTopToBottom();
                    } else {
                        onSwipeBottomToTop();
                    }
                }
                result = true;

            } catch (Exception exception) {
                exception.printStackTrace();
            }
            return result;
        }
    }

    public void onSwipeLeftToRight() {
        boolean isVisible = layoutToShowHide.getVisibility() == View.VISIBLE;
        if ((swipeDirections.contains(SwipeDirection.leftToRight) && isVisible) || (swipeDirections.contains(SwipeDirection.rightToLeft) && !isVisible))
            toggleViewVisibilityWithAnimation(SwipeDirection.leftToRight);
    }

    public void onSwipeRightToLeft() {
        boolean isVisible = layoutToShowHide.getVisibility() == View.VISIBLE;
        if ((swipeDirections.contains(SwipeDirection.rightToLeft) && isVisible) || (swipeDirections.contains(SwipeDirection.leftToRight) && !isVisible))
            toggleViewVisibilityWithAnimation(SwipeDirection.rightToLeft);
    }

    public void onSwipeBottomToTop() {
        boolean isVisible = layoutToShowHide.getVisibility() == View.VISIBLE;
        if ((swipeDirections.contains(SwipeDirection.bottomToTop) && isVisible) || (swipeDirections.contains(SwipeDirection.topToBottom) && !isVisible))
            toggleViewVisibilityWithAnimation(SwipeDirection.bottomToTop);
    }

    public void onSwipeTopToBottom() {
        boolean isVisible = layoutToShowHide.getVisibility() == View.VISIBLE;
        if ((swipeDirections.contains(SwipeDirection.topToBottom) && isVisible) || (swipeDirections.contains(SwipeDirection.bottomToTop) && !isVisible))
            toggleViewVisibilityWithAnimation(SwipeDirection.topToBottom);
    }

    void toggleViewVisibilityWithAnimation(SwipeDirection swipeDirection) {

        int currenVisibility = layoutToShowHide.getVisibility();
        int deltaVal = swipeDirection == SwipeDirection.leftToRight || swipeDirection == SwipeDirection.topToBottom ? 1000 : -1000;
        if (currenVisibility == View.GONE) {
            deltaVal = -deltaVal;
        }

        int fromXDelta = currenVisibility == View.VISIBLE || swipeDirection == SwipeDirection.topToBottom || swipeDirection == SwipeDirection.bottomToTop ? 0 : deltaVal;
        int toXDelta = currenVisibility == View.GONE || swipeDirection == SwipeDirection.topToBottom || swipeDirection == SwipeDirection.bottomToTop ? 0 : deltaVal;
        int fromYDelta = currenVisibility == View.VISIBLE || swipeDirection == SwipeDirection.leftToRight || swipeDirection == SwipeDirection.rightToLeft ? 0 : deltaVal;
        int toYDelta = currenVisibility == View.GONE || swipeDirection == SwipeDirection.leftToRight || swipeDirection == SwipeDirection.rightToLeft ? 0 : deltaVal;

        Animation animation = new TranslateAnimation(fromXDelta, toXDelta,fromYDelta, toYDelta);
        animation.setDuration(500);
        layoutToShowHide.startAnimation(animation);
        layoutToShowHide.setVisibility(toXDelta == 0 && toYDelta == 0 ? View.VISIBLE : View.GONE);
    }
}

How to Use this Class in Java

You can add the swipe functionality to any of your layouts by calling the initialize method of the above SwipeLayoutToHideAndShow class. The details about the parameters are explained below.

SwipeLayoutToHideAndShow swipeLayoutToHideAndShow = new SwipeLayoutToHideAndShow();
swipeLayoutToHideAndShow.initialize(rootLayout, movingLayout, Arrays.asList(SwipeLayoutToHideAndShow.SwipeDirection.rightToLeft, SwipeLayoutToHideAndShow.SwipeDirection.leftToRight, SwipeLayoutToHideAndShow.SwipeDirection.topToBottom, SwipeLayoutToHideAndShow.SwipeDirection.bottomToTop), 50);

Paramters in the initialize method

As you can see in your class code there is a function initialize(…) that we need to call to activate swipe gesture on our layout. The explanation of the parameters is that the first parameter is the root layout. You can any layout here on which you want to handle the swipe gesture. 2nd parameter is the moving layout, that layout will move with the swipe gesture. The last parameter takes the array of all possible swipe directions you want to allow in your scenario. In the following code, All 4 types are passed so the layout will be able to move in all directions. But you can pass only those swipe directions which you want to allow in your case. These swipe direction types are already defined in an Interface inside the above class.

Cancel the Swipe Gesture Listener

You can cancel the swipe gesture by just call the cancel() method, as shown in the following code.

swipeLayoutToHideAndShow.cancel();

This utility class uses GestureDetector and OnTouchListener for handling the gestures. But we don’t need to go to the inner implementation of the SwipeLayoutToHideAndShow class code as it seems not required for now.

That’s it. Enjoy 🙂

If you have any question feel free to ask in the following comments section.

Next:

Upload File to Server in Android

Please share this post:
Native Mobile Application Developer (Android + IOS) having experience in Java, Swift, Kotlin, Objective C, Unity, C#, C/C++, NODE JS & PHP.

Ask a Question

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Related Posts

Begin typing your search term above and press enter to search. Press ESC to cancel.

%d bloggers like this: