Android Swipe Functionality

I needed to allow my easy receipt app to do a few simple things.

-A way for the user to review the receipts that was swipe-able.

-This view needed to show data and an image

-It needed left right detection as well

 

The basic components for this are as follows;

Layouts-

I used two main layout files plus others. A linear layout to hold our swipe-able layouts, a coordinator layout which is required to detect the swipe dismiss behavior and get swiped away, plus other various layouts that go inside the coordinator layout.

Here is my linear layout container

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/coordinator_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.signal.cagney.easyreceipt.Util.LinearInterceptLayout
        android:id="@+id/linearContainer"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

    </com.signal.cagney.easyreceipt.Util.LinearInterceptLayout>



</RelativeLayout>

Here is my coordinator layout. Notice I used frame layout on the top for my textviews and buttons and a zoomable image view on the bottom which is not a standard android class.

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">


       <android.support.design.widget.CoordinatorLayout
           android:id="@+id/coordinator_forswipe"
           android:layout_width="match_parent"
           android:layout_height="match_parent"
           xmlns:app="http://schemas.android.com/apk/res-auto"       >


        <android.support.design.widget.AppBarLayout
            android:id="@+id/appbar_Main"
            android:layout_width="match_parent"
            android:layout_height="340dp"
            android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

            <android.support.design.widget.CollapsingToolbarLayout
                android:id="@+id/collapsingToolbar"
                android:layout_height="match_parent"
                android:layout_width="match_parent"
                app:layout_scrollFlags="scroll|exitUntilCollapsed"
                app:contentScrim="@color/colorAccent"
                app:expandedTitleMargin="48dp"
                app:expandedTitleMarginEnd="64dp">


                <FrameLayout
                    android:background="@color/colorBackground"
                    android:id="@+id/framelayout_Conatiner_Details"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    />



                <android.support.v7.widget.Toolbar
                    android:id="@+id/toolbar_Main"
                    android:layout_height="?android:attr/actionBarSize"
                    android:layout_width="match_parent"
                    app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
                    app:layout_collapseMode="pin"

                    />


            </android.support.design.widget.CollapsingToolbarLayout>


        </android.support.design.widget.AppBarLayout>


                  <android.support.v4.widget.NestedScrollView
                      android:id="@+id/nestedScrollView_Image"
                      android:layout_width="match_parent"
                      android:layout_height="match_parent"
                      app:layout_behavior="@string/appbar_scrolling_view_behavior">


                      <com.signal.cagney.easyreceipt.Util.ZoomableImageView
                          android:adjustViewBounds="true"
                          android:scaleType="fitCenter"
                          android:id="@+id/imageView_UpperImage"
                          android:layout_width="match_parent"
                          android:layout_height="match_parent"
                          app:layout_collapseMode="parallax"
                          />





                </android.support.v4.widget.NestedScrollView>






            </android.support.design.widget.CoordinatorLayout>



        </android.support.design.widget.CoordinatorLayout>

The java –

In order to get the swipe direction I had to create a custom swipe dismiss behavior class to get the callback direction.

In my fragment I used this code to set up the custom swipe dismiss behavior onto my coordinator layout.

private void setUPUI()
{
    Log.d(TAG, "setUPUI: ");
    final CustomSwipDismissBehavior mSwipe = new CustomSwipDismissBehavior();


    mSwipe.setSwipeDirection(SwipeDismissBehavior.SWIPE_DIRECTION_ANY);
    mSwipe.setSensitivity(.1f);
    mSwipe.setDragDismissDistance(.9f);
    swiper = mSwipe;

    mSwipe.setListener(new SwipeDismissBehavior.OnDismissListener() {

        @Override
        public void onDismiss(View view) {

           int i = mSwipe.getDirection();
            Log.d(TAG, "onDismiss: ---------------- " + String.valueOf(i));

            if (i == 2){


                   //left swipe


            }else {

                 //right swipe

            }



        }

        @Override
        public void onDragStateChanged(int state) {

        }
    });

 

But in order to get the direction which I could not find a way to do with androids standard setup I had to make a custom swipe dismiss behavior like so.

 

public class CustomSwipDismissBehavior extends SwipeDismissBehavior{

    private final String TAG = "CustomSwipeBehavior";

    public final static int IDLE = 0;
    public final static int LEFT = 1;
    public final static int RIGHT = 2;

    float x1, x2;
    float minimum = 0;

    //1 left, 2 = right
    int direction = 1;

    boolean acceptswipe = true;

    @Override
    public void setListener(OnDismissListener listener) {
        super.setListener(listener);
    }


    @Override
    public boolean onInterceptTouchEvent(CoordinatorLayout parent, View child, MotionEvent event) {
        //Log.d(TAG, "onInterceptTouchEvent: " + event);
        setDirection(event);
        return super.onInterceptTouchEvent(parent, child, event);
    }

    @Override
    public boolean onTouchEvent(CoordinatorLayout parent, View child, MotionEvent event) {
        setDirection(event);

            return super.onTouchEvent(parent, child, event);


    }


    @Override
    public boolean canSwipeDismissView(@NonNull View view) {


        if (acceptswipe) {
            Log.d(TAG, "onTouchEvent: 1");
        return super.canSwipeDismissView(view);
        }else {
            Log.d(TAG, "onTouchEvent: 2");
            return false;
        }

    }

    @Override
    public void setSensitivity(float sensitivity) {
        super.setSensitivity(sensitivity);
        if (sensitivity == 0.0f){
            acceptswipe = false;
        }else{
            acceptswipe = true;
        }

    }

    private void setDirection(MotionEvent event)
    {
        //Log.d(TAG, "setDirection: motion event =  " + event);
        switch (event.getAction()){

            case MotionEvent.ACTION_DOWN:
                if (x1 == 0) {
                    x1 = event.getX();
                    //Log.d(TAG, "calculate: x1: " + String.valueOf(x1));
                }
                break;

            case MotionEvent.ACTION_MOVE:
                if (x1 == 0) {
                    x1 = event.getX();
                    //Log.d(TAG, "calculate: x1: " + String.valueOf(x1));
                }
                break;

            case MotionEvent.ACTION_UP:
                x2 = event.getX();
               //Log.d(TAG, "calculate: x2 : " + String.valueOf(x2));
               calculate(x1, x2);
                break;
        }

    }


    private void calculate(float x1, float x2)
    {


        float delta = x1 - x2;

        //Log.d(TAG, "calculate: x1: " + String.valueOf(x1) + "  x2: " + String.valueOf(x2) + "  delta: " + String.valueOf(delta));

        if (delta > minimum){
            direction = LEFT;
        }
        else if (delta < -minimum){
            direction = RIGHT;
        }
        else{
            direction = IDLE;
        }

        x1 = 0;
        x2 = 0;

        //Log.d(TAG, "calculate: " + direction);

    }




    public int getDirection()
    {
        int temp = direction;
        direction = IDLE;

        return temp;

    }




}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Leave a Reply

Your email address will not be published. Required fields are marked *