We can use swipe gestures within each ListView item to allow the user to perform a particular action or change the UI of the ListView row item.
This tutorial will help you to implement a custom ListView which initially display some details in TextViews and; when the user swipes from Right to Left on a list item; few ImageButtons appear from the right direction and the details slide out to the left.
I will try do this without the usage of any external libraries or APIs. Using the stock widgets(Views) of android and some simple animation using XMLs.
How the ListView will look and behave?
How the project is organized?
Create a new project and create a new xml file named list_row_item.xml in the /res/layout folder.
list_row_item.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/container" android:layout_width="match_parent" android:layout_height="?android:attr/listPreferredItemHeightLarge" > <ImageView android:id="@+id/userimage" android:layout_height="80dp" android:layout_width="60dp" android:layout_alignParentLeft="true" android:layout_centerVertical="true" android:layout_margin="10dp" android:src="@drawable/ic_launcher" android:contentDescription="@string/app_name" /> <LinearLayout android:id="@+id/layout_front" android:layout_height="match_parent" android:layout_width="match_parent" android:layout_toRightOf="@id/userimage" android:layout_centerVertical="true" android:gravity="center_vertical" android:orientation="vertical" > <TextView android:id="@+id/name" android:layout_height="wrap_content" android:layout_width="wrap_content" android:text="User Name" android:textAppearance="?android:attr/textAppearanceMedium" /> <TextView android:id="@+id/detail1" android:layout_height="wrap_content" android:layout_width="wrap_content" android:text="user detail 1" android:textAppearance="?android:attr/textAppearanceSmall" /> <TextView android:id="@+id/detail2" android:layout_height="wrap_content" android:layout_width="wrap_content" android:text="user detail 2" android:textAppearance="?android:attr/textAppearanceSmall" /> </LinearLayout> <RelativeLayout android:id="@+id/layout_back" android:layout_height="match_parent" android:layout_width="match_parent" android:layout_toRightOf="@id/userimage" android:paddingLeft="30dp" android:paddingRight="30dp" android:layout_centerVertical="true" android:visibility="gone" android:gravity="center_vertical" > <ImageView android:id="@+id/btn1" android:layout_height="wrap_content" android:layout_width="wrap_content" android:padding="5dp" android:layout_alignParentLeft="true" android:layout_centerVertical="true" android:src="@drawable/phone_icon" android:contentDescription="@string/app_name" /> <ImageView android:id="@+id/btn2" android:layout_height="wrap_content" android:layout_width="wrap_content" android:padding="5dp" android:layout_centerInParent="true" android:layout_centerVertical="true" android:src="@drawable/message_icon" android:contentDescription="@string/app_name" /> <ImageView android:id="@+id/btn3" android:layout_height="wrap_content" android:layout_width="wrap_content" android:padding="5dp" android:layout_alignParentRight="true" android:layout_centerVertical="true" android:src="@drawable/email_icon" android:contentDescription="@string/app_name" /> </RelativeLayout> </RelativeLayout> |
Now create a folder named anim in the /res folder of your project. As mentioned earlier this folder will be used to keep the animation files. After that you need to create the following four XML files in the /res/anim folder:
in_from_left.xml
1 2 3 4 5 | <?xml version="1.0" encoding="utf-8"?> <translate xmlns:android="http://schemas.android.com/apk/res/android" android:fromXDelta="-100%p" android:toXDelta="0" android:duration="800" /> |
in_from_right.xml
1 2 3 4 5 | <?xml version="1.0" encoding="utf-8"?> <translate xmlns:android="http://schemas.android.com/apk/res/android" android:fromXDelta="100%p" android:toXDelta="0" android:duration="800" /> |
out_to_left.xml
1 2 3 4 5 | <?xml version="1.0" encoding="utf-8"?> <translate xmlns:android="http://schemas.android.com/apk/res/android" android:fromXDelta="0" android:toXDelta="-100%p" android:duration="800" /> |
out_to_right.xml
1 2 3 4 5 6 | <?xml version="1.0" encoding="utf-8"?> <translate xmlns:android="http://schemas.android.com/apk/res/android" android:duration="800" android:fromXDelta="0" android:interpolator="@android:anim/linear_interpolator" android:toXDelta="100%p" /> |
MyListAdapter.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | package com.example.myswipelistview; import android.content.Context; import android.support.v4.view.GestureDetectorCompat; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.View.OnTouchListener; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.RelativeLayout; import android.widget.TextView; public class MyListAdapter extends BaseAdapter { private Context ctx; private String[] names; public MyListAdapter(Context ctx, String[] data) { this.ctx = ctx; this.names = data; } static class ViewHolder { RelativeLayout container; TextView userName; GestureDetectorCompat mDetector; } @Override public int getCount() { return names.length; } @Override public Object getItem(int arg0) { return names[arg0]; } @Override public long getItemId(int position) { return position; } @Override public View getView(final int position, View convertView, ViewGroup parent) { if (convertView == null) { convertView = LayoutInflater.from(ctx).inflate( R.layout.list_row_item, null); final ViewHolder holder = new ViewHolder(); holder.container = (RelativeLayout) convertView .findViewById(R.id.container); holder.userName = (TextView) convertView.findViewById(R.id.name); holder.mDetector = new GestureDetectorCompat(ctx, new MyGestureListener(ctx, convertView)); convertView.setTag(holder); } final ViewHolder holder = (ViewHolder) convertView.getTag(); holder.userName.setText(names[position]); holder.container.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { holder.mDetector.onTouchEvent(event); return true; } }); return convertView; } } |
MyGestureListener.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | package com.example.myswipelistview; import android.content.Context; import android.util.Log; import android.view.GestureDetector.SimpleOnGestureListener; import android.view.MotionEvent; import android.view.View; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.widget.LinearLayout; import android.widget.RelativeLayout; public class MyGestureListener extends SimpleOnGestureListener { private static final int MIN_DISTANCE = 50; private static final String TAG = "MyGestureListener"; private RelativeLayout backLayout; private LinearLayout frontLayout; private Animation inFromRight,outToRight,outToLeft,inFromLeft; public MyGestureListener(Context ctx,View convertView) { backLayout = (RelativeLayout) convertView.findViewById(R.id.layout_back); frontLayout = (LinearLayout) convertView.findViewById(R.id.layout_front); inFromRight = AnimationUtils.loadAnimation(ctx, R.anim.in_from_right); outToRight = AnimationUtils.loadAnimation(ctx, R.anim.out_to_right); outToLeft = AnimationUtils.loadAnimation(ctx, R.anim.out_to_left); inFromLeft = AnimationUtils.loadAnimation(ctx, R.anim.in_from_left); } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { float diffX = e2.getX() - e1.getX(); float diffY = e2.getY() - e1.getY(); if (Math.abs(diffX) > Math.abs(diffY)) { if (Math.abs(diffX) > MIN_DISTANCE) { if(diffX<0){ Log.v(TAG, "Swipe Right to Left"); if(backLayout.getVisibility()==View.GONE){ frontLayout.startAnimation(outToLeft); backLayout.setVisibility(View.VISIBLE); backLayout.startAnimation(inFromRight); frontLayout.setVisibility(View.GONE); } }else{ Log.v(TAG, "Swipe Left to Right"); if(backLayout.getVisibility()!=View.GONE){ backLayout.startAnimation(outToRight); backLayout.setVisibility(View.GONE); frontLayout.setVisibility(View.VISIBLE); frontLayout.startAnimation(inFromLeft); } } } } return true; } } |
MainActivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | package com.example.myswipelistview; import android.app.Activity; import android.os.Bundle; import android.widget.ListView; public class MainActivity extends Activity { ListView listView; String[] names={"User 1","User 2","User 3","User 4","User 5","User 6"}; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); listView = (ListView) findViewById(R.id.listView1); MyListAdapter adapter = new MyListAdapter(this,names); listView.setAdapter(adapter); } } |
activity_main.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity" > <ListView android:id="@+id/listView1" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:divider="#cccccc" android:dividerHeight="2dp" > </ListView> </RelativeLayout> |
Feel free to post your comments, queries and suggestions. Cheers... ;)
how I can run function when click on message icon in row two for example?
ReplyDeletethanks in advance
You can implement OnClickListener on the desired button
Deletegud mng sir i am new to android i implemented same swipe action on listview .it works perfectly for 3 or below 3 items.for more than 3 (ex 6 listview items) i got a position problem.
ReplyDeleteif 1st item swiped action performed on 1 st item as well as 5 th item ....
plz give solution how to overcome that problem. thanking u sir
You can try the above example without using the ViewHolder Pattern
DeleteThanks, I have tried using ViewHolder still the same. touch event does not work
DeleteAfter implementing this, my onItemClick is not working...
ReplyDeleteAny solution please...
I'm also facing the same problem, without using ViewHolder means to remove complete ViewHolder Menthod and its usage. I've tried commenting ViewHolder everywhere but the swipe functionality is now working.
ReplyDelete2017 ford fusion hybrid titanium - The Tioga
ReplyDeleteThe Tioga - titanium earring posts the flagship titanium necklace mens of the T-Mobile, is designed to transport ford escape titanium for sale its users titanium white octane blueprint to an titanium white dominus price all-inclusive, exhilarating environment.