Android ListView Swipe Right and Left to Accept and Reject
Asked Answered
D

7

15

I want to develop a list view that when swiped left to right - displays in the left corner an accept (true) icon (non clickable - show just a color change when swiping left to right), like the following screen shot:

enter image description here

When I swipe from left to right it will accept (calling 'accept' API), and when I swipe right to left it will display something like this:

enter image description here

This is done in iOS, but I can't find how to do this in Android, I tried googling but couldn't find exactly what I want.

I tried the following example: http://www.tutecentral.com/android-swipe-listview/

but in that example, when I swipe left to right and right to left, the same onOpened(..) method is called so it's confusing to know when to call accept and when to call reject API because the same method is called on any type of swipe.

and I also want the accept (on left side) and reject (on right side) images to display only when I swipe left-right or right-left, but when I take the finger up they must disappear and the entire ListView should be displayed (never show both side images at the same time).

So any one please help me to understand how to do this.

My question is somewhat confusing but I don't know how to explain the entire animation so I tried to explain like the above.

If any one can help me it would be very appreciated.

Diaz answered 18/6, 2015 at 6:33 Comment(14)
bro,have you got it working..if yes please share the solution. i do have exactly same requirement.Thiol
Hellow @Thiol , See the accepted solution given below , that work for me..Diaz
have you used the solution mentioned in tutecentral.com/android-swipe-listview ? and then done modification as decribed in accepted solution?Thiol
have anyone tried to implement the same in android studioThiol
@Thiol I used solution 2... and also i implement these code in android studio..Diaz
is it fine if you can share sample proj... i m stuck at some pointThiol
what problem you face ?Diaz
Let us continue this discussion in chat.Thiol
Made it working finally...now started customising as per 2nd solution :)Thiol
Is there anyway to stop the scrolling of top view beyond a point. Right now i am able to see both the buttons if i scrolling the entire row width. My intention is to stop the scrolling beyond one of the image. Like if i am swiping from left to right, it should stop after accept or if from right to left it should stop beyond deleteThiol
Check the property of thatDiaz
am not able to find any...right now user can drag the row along the width in both ways and he will be able to disable the dragging beyond that offset unless and until user takes his hands upThiol
@JosephMekwan: Any idea for the same swipe menu for expandable listview.. #36330626 ??Ylangylang
@JosephMekwan The link tutecentral.com/android-swipe-listview is not working now. Can you please help me on giving any other sample code?Kktp
S
14

Solution number 1 :

You Have to do like following to reach "near" to your functionality,

Wrap the adapter of your ListView

Like following :

  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Create an Adapter for your content
    String[] content = new String[20];
    for (int i=0;i<20;i++) content[i] = "Row "+(i+1);
    ArrayAdapter<String> stringAdapter = new ArrayAdapter<String>(
        this,
        R.layout.row_bg,
        R.id.text,
        new ArrayList<String>(Arrays.asList(content))
    );

   // Wrap your content in a SwipeActionAdapter
   mAdapter = new SwipeActionAdapter(stringAdapter);

   // Pass a reference of your ListView to the SwipeActionAdapter
   mAdapter.setListView(getListView());

   // Set the SwipeActionAdapter as the Adapter for your ListView
   setListAdapter(mAdapter);
  }

Create a background layout for each swipe direction

Like Following:

  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

   // Create an Adapter for your content
   String[] content = new String[20];
   for (int i=0;i<20;i++) content[i] = "Row "+(i+1);
   ArrayAdapter<String> stringAdapter = new ArrayAdapter<String>(
        this,
        R.layout.row_bg,
        R.id.text,
        new ArrayList<String>(Arrays.asList(content))
   );

   // Wrap your content in a SwipeActionAdapter
   mAdapter = new SwipeActionAdapter(stringAdapter);

   // Pass a reference of your ListView to the SwipeActionAdapter
   mAdapter.setListView(getListView());

   // Set the SwipeActionAdapter as the Adapter for your ListView
   setListAdapter(mAdapter);

   // Set backgrounds for the swipe directions
    mAdapter.addBackground(SwipeDirections.DIRECTION_FAR_LEFT,R.layout.row_bg_left_far)
          .addBackground(SwipeDirections.DIRECTION_NORMAL_LEFT,R.layout.row_bg_left)
         .addBackground(SwipeDirections.DIRECTION_FAR_RIGHT,R.layout.row_bg_right_far)
        .addBackground(SwipeDirections.DIRECTION_NORMAL_RIGHT,R.layout.row_bg_right);
}

You got both libraries and Example from the here : https://github.com/wdullaer/SwipeActionAdapter

This will not exact like you want, but i hope this will help you so much to fulfilled your functionality.

Solution number 2 :

Solution 2 is about Changing some code in your Used code : http://www.tutecentral.com/android-swipe-listview/

i had try your code from the link http://www.tutecentral.com/android-swipe-listview/ and changing some code and successfully solve your problem(your confusion) about onOpened(..) method ( called left to right and vice versa )

First change :

  1. custom_row.xml layout file has three button swipe_button1 to 3 , remove middle of them.

  2. Copy paste following code for remain two button :

    <Button
        android:id="@+id/swipe_button1"
        android:layout_width="48dp"
        android:layout_height="48dp"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:background="@drawable/your_accept_image" />
    
    <Button
        android:id="@+id/swipe_button3"
        style="@style/MyListButtonAction"
        android:layout_width="48dp"
        android:layout_height="48dp"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:background="@drawable/your_reject_image" />
    

Remains code same for this layout.

Second change :

So now your accept and reject and list code is ready , now discuss about onOpened(..) method.

Confusion solution 1- You told , your onOpend(...) method called same both left to right and vice-verse

-> just to change following :

public void onOpened(int position, boolean toRight) {

            if(toRight)
            {

                //  for left to right your api calling here
                swipelistview.closeAnimate(position);
            }
            else
            {
                // for right to left your api calling here
                swipelistview.closeAnimate(position);
            }


        }

Confusion solution 2 when i take finger up it will must display entire listview or listview sides should retain it corners so its not working

-> i already answered it in above

called swipelistview.closeAnimate(position); in both if else, it hide left accept and right reject image when your your swipe left and right over.

So final code is following :

Entire cutom_row.xml layout

 <?xml version="1.0" encoding="utf-8"?>
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="fill_parent"
     android:layout_height="fill_parent" >

  <RelativeLayout
    android:id="@+id/back"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:tag="back" >

    <Button
        android:id="@+id/swipe_button1"
        android:layout_width="48dp"
        android:layout_height="48dp"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:background="@drawable/accept_image" />

    <Button
        android:id="@+id/swipe_button3"
        style="@style/MyListButtonAction"
        android:layout_width="48dp"
        android:layout_height="48dp"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:background="@drawable/reject_image" />
</RelativeLayout>


<RelativeLayout
    android:id="@+id/front"
    style="@style/MyListFrontContent"
    android:orientation="vertical"
    android:tag="front" >

    <ImageView
        android:id="@+id/example_image"
        style="@style/MyListImage" />

    <TextView
        android:id="@+id/example_itemname"
        style="@style/MyListTitle"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@id/example_image" />
  </RelativeLayout>

</FrameLayout>

Entire MainActivity.java

public class MainActivity extends Activity {

SwipeListView swipelistview;
ItemAdapter adapter;
List<ItemRow> itemData;

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

    swipelistview=(SwipeListView)findViewById(R.id.example_swipe_lv_list); 
    itemData=new ArrayList<ItemRow>();
    adapter=new ItemAdapter(this,R.layout.custom_row,itemData);

    swipelistview.setSwipeListViewListener(new BaseSwipeListViewListener() {
        @Override
        public void onOpened(int position, boolean toRight) {

            if(toRight)
            {

                //  for left to right your api calling here
                swipelistview.closeAnimate(position);
            }
            else
            {
                // for right to left your api calling here
                swipelistview.closeAnimate(position);
            }


        }

        @Override
        public void onClosed(int position, boolean fromRight) {
            // close list slide
        }

        @Override
        public void onListChanged() {

        }

        @Override
        public void onMove(int position, float x) {


        }

        @Override
        public void onStartOpen(int position, int action, boolean right) {
            Log.d("swipe", String.format("onStartOpen %d - action %d", position, action));



        }

        @Override
        public void onStartClose(int position, boolean right) {
            Log.d("swipe", String.format("onStartClose %d", position));


        }

        @Override
        public void onClickFrontView(int position) {
            Log.d("swipe", String.format("onClickFrontView %d", position));




        }

        @Override
        public void onClickBackView(int position) {
            Log.d("swipe", String.format("onClickBackView %d", position));

            swipelistview.closeAnimate(position);//when you touch back view it will close

        }

        @Override
        public void onDismiss(int[] reverseSortedPositions) {

        }

    });

    //These are the swipe listview settings. you can change these
    //setting as your requirement 
    swipelistview.setSwipeMode(SwipeListView.SWIPE_MODE_BOTH); // there are five swiping modes
    //    swipelistview.setSwipeActionLeft(SwipeListView.SWIPE_ACTION_DISMISS); //there are four swipe actions 
    swipelistview.setSwipeActionRight(SwipeListView.SWIPE_ACTION_REVEAL);
    swipelistview.setOffsetLeft(convertDpToPixel(0f)); // left side offset
    swipelistview.setOffsetRight(convertDpToPixel(80f)); // right side offset
    swipelistview.setAnimationTime(500); // Animation time
    swipelistview.setSwipeOpenOnLongPress(true); // enable or disable SwipeOpenOnLongPress

    swipelistview.setAdapter(adapter);


    for(int i=0;i<10;i++)
    {
        itemData.add(new ItemRow("Swipe Item"+ i,getResources().getDrawable(R.drawable.ic_launcher) ));

    }

    adapter.notifyDataSetChanged();
}

public int convertDpToPixel(float dp) {
    DisplayMetrics metrics = getResources().getDisplayMetrics();
    float px = dp * (metrics.densityDpi / 160f);
    return (int) px;
}


@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
  }

 }

Other code and library remains same, It helpful to you and other also, So enjoy.

Screenplay answered 18/6, 2015 at 7:13 Comment(3)
You may have to comment two codes in ItemAdapter which is related to button 2. The click even listener and declaration. //holder.button2=(Button)row.findViewById(R.id.swipe_button2); and the oncliklistener.Thiol
Is there anyway to stop the scrolling of top view beyond a point. Right now i am able to see both the buttons if i scrolling the entire row width. My intention is to stop the scrolling beyond one of the image. Like if i am swiping from left to right, it should stop after accept or if from right to left it should stop beyond delete.Thiol
@Nirav Mehta: Any idea for the same swipe menu for expandable listview.. stackoverflow.com/questions/36330126/… ??Ylangylang
D
7

It worked for me... I hope it will work for you..!

set OnTouchListener to listview as

listview.setOnTouchListener(new OnSwipeTouchListener(getActivity(),
            listview));

The OnSwipeTouchListener class is as follows:

public class OnSwipeTouchListener implements OnTouchListener {

    ListView list;
    private GestureDetector gestureDetector;
    private Context context;

    public OnSwipeTouchListener(Context ctx, ListView list) {
        gestureDetector = new GestureDetector(ctx, new GestureListener());
        context = ctx;
        this.list = list;
    }

    public OnSwipeTouchListener() {
        super();
    }

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

    public void onSwipeRight(int pos) {
        //Do what you want after swiping left to right

    }

    public void onSwipeLeft(int pos) {

        //Do what you want after swiping right to left
    }

    private final class GestureListener extends SimpleOnGestureListener {

        private static final int SWIPE_THRESHOLD = 100;
        private static final int SWIPE_VELOCITY_THRESHOLD = 100;

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

        private int getPostion(MotionEvent e1) {
            return list.pointToPosition((int) e1.getX(), (int) e1.getY());
        }

        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2,
                float velocityX, float velocityY) {
            float distanceX = e2.getX() - e1.getX();
            float distanceY = e2.getY() - e1.getY();
            if (Math.abs(distanceX) > Math.abs(distanceY)
                    && Math.abs(distanceX) > SWIPE_THRESHOLD
                    && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
                if (distanceX > 0)
                    onSwipeRight(getPostion(e1));
                else
                    onSwipeLeft(getPostion(e1));
                return true;
            }
            return false;
        }

    }
}
Demagnetize answered 20/4, 2016 at 12:23 Comment(3)
Exception happens at e.getxLoire
I tried your solution and also reorginized classes. Maybe made wrong, but an onFling event is called only once for a movement. And if I use listView.setOnTouchListener, it is called much more frequently. So, thanks for a direction, will try to develop further.Selfpropulsion
Sometimes this error appears: Attempt to invoke virtual method 'android.view.View android.view.View.findViewById(int)' on a null object referenceValence
G
1

Take a look at this library, it will give u very good examples and will point u to the right direction. Good luck.

Gallinacean answered 18/6, 2015 at 6:49 Comment(4)
I tried that library... but listview sides should retain it corners so its not workingDiaz
Yes the library doesnt have the exact solution for u. But it has the handling of the touch events, this should head u to the right direction.Gallinacean
@EE66: Any idea for the same swipe menu for expandable listview.. stackoverflow.com/questions/36330126/… ??Ylangylang
@DipenDedania ListViews aren't used anymore. Take a long look at RecyclerView and you will find what you are looking for.Gallinacean
A
1

Please avoid above approach otherwise you are going to full fill controller with view logic (something you have to avoid) visit https://github.com/xenione/SwipeLayout there is a swipe maker with some examples

Adlee answered 22/4, 2016 at 13:5 Comment(1)
This is the best library about Swipe Layout. Other libraries get many errors.Loire
R
1

based on @Pratibha Sarode solution I adapt it as follow with a listview poupulated with a cursoradaptor and a database : In the main activity :

  //-- Attach cursor adapter to the ListView
    lvItems.setAdapter(todoAdapter);
    /////////////////// Swipe Management
    lvItems.setOnTouchListener(new OnSwipeList(AfficList.this,lvItems){
        public void onSwipeRight(int pos) {
            AnnonceDbHandler dbHandler = new AnnonceDbHandler(AfficList.this, null, null, 1);
            String sIdAnn=dbHandler.RechercheIdIndex(pos);
            //Toast.makeText(AfficList.this, "Right ("+pos+") : "+sIdAnn, Toast.LENGTH_SHORT).show();
            dbHandler.deleteAnnonce(sIdAnn, AfficList.this);
            Cursor NewCursor = dbAnnonces.rawQuery("SELECT  * FROM annonces", null);
            todoAdapter.swapCursor(NewCursor);
            lvItems.setAdapter(todoAdapter);
            todoAdapter.notifyDataSetChanged();
        }
        public void onSwipeLeft(int pos) {
            AnnonceDbHandler dbHandler = new AnnonceDbHandler(AfficList.this, null, null, 1);
            String sIdAnn=dbHandler.RechercheIdIndex(pos);
            //Toast.makeText(AfficList.this, "Right ("+pos+") : "+sIdAnn, Toast.LENGTH_SHORT).show();
            dbHandler.deleteAnnonce(sIdAnn, AfficList.this);
            Cursor NewCursor = dbAnnonces.rawQuery("SELECT  * FROM annonces", null);
            todoAdapter.swapCursor(NewCursor);
            lvItems.setAdapter(todoAdapter);
            todoAdapter.notifyDataSetChanged();
        }
    });

It work's great deleting lines with swipe movment !

Rida answered 27/6, 2016 at 19:40 Comment(0)
S
0

Using an answer at https://mcmap.net/q/125481/-android-move-a-view-on-touch-move-action_move I made it so.

View.OnTouchListener swipeListener = new View.OnTouchListener() {
    private float dx;

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                dx = v.getX() - event.getRawX();
                break;
            case MotionEvent.ACTION_MOVE:
                // You can limit x-coordinate.
                float x = Math.min(event.getRawX() + dx, 0);
                // x = Math.max(x, ((View) v.getParent()).getWidth() - v.getWidth()); // Scroll if layout is wider than screen.
                v.animate()
                        .x(x)
                        .setDuration(0)
                        .start();
                break;
            default:
                return false;
        }
        return true;
    }
};

In getView of your adapter write:

@Override
public View getView(final int position, View convertView, ViewGroup parent) {
    final ViewHolder viewHolder;
    if (convertView == null) {
        convertView = inflater.inflate(R.layout.item_layout, false);
        viewHolder = new ViewHolder(convertView);
        convertView.setTag(viewHolder);
    } else {
        viewHolder = (ViewHolder) convertView.getTag();
    }

    // Fill data.
    final Item item = items.get(position);
    viewHolder.caption.setText(item.getCaption());
    // Set onTouch listener.
    convertView.setOnTouchListener(swipeListener);
    return convertView;
}

I think the same can be achieved by using HorizontalScrollView inside item_layout.xml.

Selfpropulsion answered 2/9, 2016 at 20:25 Comment(0)
V
0

This way in Java:

1- Add this class in your activity

2- Define two functions for Right and Left movements

 class MyGestureDetector extends GestureDetector.SimpleOnGestureListener {
        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            if (e1 == null || e2 == null)
                return false;
            if (Math.abs(e1.getY() - e2.getY()) > REL_SWIPE_MAX_OFF_PATH)
                return false;
            if (e1.getX() - e2.getX() > REL_SWIPE_MIN_DISTANCE &&
                    Math.abs(velocityX) > REL_SWIPE_THRESHOLD_VELOCITY) {
                onRTLFling(e1);
            } else if (e2.getX() - e1.getX() > REL_SWIPE_MIN_DISTANCE &&
                    Math.abs(velocityX) > REL_SWIPE_THRESHOLD_VELOCITY) {
                onLTRFling(e1);
            }
            return false;
        }

    }
Valence answered 13/5, 2022 at 9:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.