Android Swipe on List Android Swipe on List android android

Android Swipe on List


I had the same problem and I didn't find my answer here.

I wanted to detect a swipe action in ListView item and mark it as swiped, while continue to support OnItemClick and OnItemLongClick.

Here is me solution:

1st The SwipeDetector class:

import android.util.Log;import android.view.MotionEvent;import android.view.View;public class SwipeDetector implements View.OnTouchListener {    public static enum Action {        LR, // Left to Right        RL, // Right to Left        TB, // Top to bottom        BT, // Bottom to Top        None // when no action was detected    }    private static final String logTag = "SwipeDetector";    private static final int MIN_DISTANCE = 100;    private float downX, downY, upX, upY;    private Action mSwipeDetected = Action.None;    public boolean swipeDetected() {        return mSwipeDetected != Action.None;    }    public Action getAction() {        return mSwipeDetected;    }    @Override    public boolean onTouch(View v, MotionEvent event) {        switch (event.getAction()) {        case MotionEvent.ACTION_DOWN:            downX = event.getX();            downY = event.getY();            mSwipeDetected = Action.None;            return false; // allow other events like Click to be processed        case MotionEvent.ACTION_UP:            upX = event.getX();            upY = event.getY();            float deltaX = downX - upX;            float deltaY = downY - upY;            // horizontal swipe detection            if (Math.abs(deltaX) > MIN_DISTANCE) {                // left or right                if (deltaX < 0) {                    Log.i(logTag, "Swipe Left to Right");                    mSwipeDetected = Action.LR;                    return false;                }                if (deltaX > 0) {                    Log.i(logTag, "Swipe Right to Left");                    mSwipeDetected = Action.RL;                    return false;                }            } else if (Math.abs(deltaY) > MIN_DISTANCE) { // vertical swipe                                                            // detection                // top or down                if (deltaY < 0) {                    Log.i(logTag, "Swipe Top to Bottom");                    mSwipeDetected = Action.TB;                    return false;                }                if (deltaY > 0) {                    Log.i(logTag, "Swipe Bottom to Top");                    mSwipeDetected = Action.BT;                    return false;                }            }            return false;        }        return false;    }}

2nd I use the swipe detector class in the list view:

    final ListView lv = getListView();    final SwipeDetector swipeDetector = new SwipeDetector();    lv.setOnTouchListener(swipeDetector);    lv.setOnItemClickListener(new OnItemClickListener() {        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {                if (swipeDetector.swipeDetected()){                    // do the onSwipe action                 } else {                    // do the onItemClick action                }            }    });    lv.setOnItemLongClickListener(new OnItemLongClickListener() {        @Override        public boolean onItemLongClick(AdapterView<?> parent, View view,int position, long id) {            if (swipeDetector.swipeDetected()){                // do the onSwipe action             } else {                // do the onItemLongClick action            }        }    });

This way I can support 3 actions - swipe, click, long click and I can use the ListView item info.

ADDED LATER:

Since ListView catches a scrolling action, it is sometimes hard to swipe. To fix it, I made the following change to SwipeDetector.onTouch:

public boolean onTouch(View v, MotionEvent event) {    switch (event.getAction()) {        case MotionEvent.ACTION_DOWN: {            downX = event.getX();            downY = event.getY();            mSwipeDetected = Action.None;            return false; // allow other events like Click to be processed        }        case MotionEvent.ACTION_MOVE: {            upX = event.getX();            upY = event.getY();            float deltaX = downX - upX;            float deltaY = downY - upY;            // horizontal swipe detection            if (Math.abs(deltaX) > HORIZONTAL_MIN_DISTANCE) {                // left or right                if (deltaX < 0) {                    Log.i(logTag, "Swipe Left to Right");                    mSwipeDetected = Action.LR;                    return true;                }                if (deltaX > 0) {                    Log.i(logTag, "Swipe Right to Left");                    mSwipeDetected = Action.RL;                    return true;                }            } else             // vertical swipe detection            if (Math.abs(deltaY) > VERTICAL_MIN_DISTANCE) {                // top or down                if (deltaY < 0) {                    Log.i(logTag, "Swipe Top to Bottom");                    mSwipeDetected = Action.TB;                    return false;                }                if (deltaY > 0) {                    Log.i(logTag, "Swipe Bottom to Top");                    mSwipeDetected = Action.BT;                    return false;                }            }             return true;        }    }    return false;}


here's a snippet I use for detecting swipes. You could then use a viewflipper to change the view.

  @Override        public boolean onTouchEvent(MotionEvent event) {            if (gestureDetector.onTouchEvent(event)) {                return true;            } else {                return false;            }        }        private static final int SWIPE_MIN_DISTANCE = 30;        private static final int SWIPE_MAX_OFF_PATH = 250;        private static final int SWIPE_THRESHOLD_VELOCITY = 200;        class MyGestureDetector extends SimpleOnGestureListener {            @Override            public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,                    float velocityY) {                try {                    if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH)                        return false;                    // right to left swipe                    if (e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE                            && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {                        leftFling();                    } else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE                            && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {                        rightFling();                    }                } catch (Exception e) {                    // nothing                }                return false;            }        }


Here is a very simplified version using the two listeners (onTouch for swipe detection, and onClickIem for item click detection)using the isSwipe flag to stop the onClickItemListener until its confirmed that is was not a swipe

Detecting the click
taking into consideration that it is not a swipe first

        listView.setOnItemClickListener(new OnItemClickListener() {            @Override            public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3)            {                if(!isSwipe)                {                    adapter.increase(arg2);                    adapter.notifyDataSetChanged();                }            }        });

Detecting the swipe

        listView.setOnTouchListener(new OnTouchListener() {        private int action_down_x = 0;            private int action_up_x = 0;            private int difference = 0;            @Override            public boolean onTouch(View v, MotionEvent event) {                switch (event.getAction()) {                    case MotionEvent.ACTION_DOWN:                        action_down_x = (int) event.getX();                        isSwipe=false;  //until now                        break;                    case MotionEvent.ACTION_MOVE:                        if(!isSwipe)                        {                            action_up_x = (int) event.getX();                            difference = action_down_x - action_up_x;                            if(Math.abs(difference)>50)                            {                                Log.d("action","action down x: "+action_down_x);                                Log.d("action","action up x: "+action_up_x);                                Log.d("action","difference: "+difference);                                //swipe left or right                                if(difference>0){                                    //swipe left                                    Log.d("action","swipe left");                                    adapter.decrease(selectedItem);                                    adapter.notifyDataSetChanged();                                }                                else{                                    //swipe right                                    Log.d("action","swipe right");                                }                                isSwipe=true;                            }                        }                        break;                    case MotionEvent.ACTION_UP:                        Log.d("action", "ACTION_UP - ");                        action_down_x = 0;                        action_up_x = 0;                        difference = 0;                        break;                }                return false;   //to allow the clicklistener to work after            }        })