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; } }