Listview rows order can be changed
using drag and drop functionality.Dragging should be enabled beyond
the visible listview position.
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="wrap_content"> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/icon" android:id="@+id/entryIcon"></ImageView> <TextView android:layout_height="wrap_content" android:id="@+id/TextView01" android:layout_width="wrap_content" android:layout_centerVertical="true" android:text="Demo description" android:layout_toRightOf="@+id/entryIcon"></TextView> </RelativeLayout>
<?xml version="1.0" encoding="utf-8"?> <AbsoluteLayout android:id="@+id/mainAbsoluteLayout" android:layout_width="fill_parent" android:layout_height="fill_parent" xmlns:android="http://schemas.android.com/apk/res/android"> <com.myself.dragndrop.CustomListView android:id="@+id/android:list" android:layout_width="fill_parent" android:layout_height="fill_parent" > </com.myself.dragndrop.CustomListView> </AbsoluteLayout>
//CustomListView.java: import java.util.ArrayList; import android.content.Context; import android.graphics.Color; import android.util.AttributeSet; import android.util.Log; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.widget.AbsListView; import android.widget.AbsoluteLayout; import android.widget.AdapterView; import android.widget.ImageView; import android.widget.ListView; import android.widget.ScrollView; import android.widget.TextView; import android.widget.AbsListView.LayoutParams; public class CustomListView extends ListView { public View moveView = null; private Context context = null; public int movedPosition = 0; public Entry moveEntry = null; public boolean isMoveFlag = false; private int firstPosition; private int lasPosition; private ArrayList<com.myself.dragndrop.CustomListView.Coordinates> listCoordinates; public CustomListView(Context context) { super(context); // TODO Auto-generated constructor stub this.context = context; setVerticalScrollBarEnabled(false); } public CustomListView(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub this.context = context; setVerticalScrollBarEnabled(true); } @Override public boolean onTouchEvent(MotionEvent ev) { // TODO Auto-generated method stub if (isMoveFlag) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: Log.v(getClass().toString(),"action_dowm"); int y = (int)ev.getY(); if (getParent() instanceof AbsoluteLayout) { AbsoluteLayout parent = (AbsoluteLayout)getParent(); if (moveView != null) { parent.removeView(DnDAdapter.emptyView); parent.addView(DnDAdapter.emptyView, new AbsoluteLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT, 0, y - 22)); } } break; case MotionEvent.ACTION_MOVE: Log.v(getClass().toString(),"action_move"); int yMove = (int)ev.getY(); if (getParent() instanceof AbsoluteLayout) { AbsoluteLayout parent = (AbsoluteLayout)getParent(); if (moveView != null) { parent.removeView(DnDAdapter.emptyView); parent.addView(DnDAdapter.emptyView, new AbsoluteLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT, 0, yMove - 22)); inChild(MotionEvent.ACTION_MOVE); } } break; case MotionEvent.ACTION_UP: if (getParent() instanceof AbsoluteLayout) { AbsoluteLayout parent = (AbsoluteLayout)getParent(); if (moveView != null) { parent.removeView(DnDAdapter.emptyView); inChild(MotionEvent.ACTION_UP); // DnDAdapter.addEntry(movedPosition); } } isMoveFlag = false; setEnabled(true); Log.v(getClass().toString(),"action_up: " + isMoveFlag); break; default: break; } } return super.onTouchEvent(ev); } @Override public void setOnScrollListener(OnScrollListener l) { // TODO Auto-generated method stub l = new OnScrollListener() { @Override public void onScrollStateChanged(AbsListView view, int scrollState) { // TODO Auto-generated method stub firstPosition = getFirstVisiblePosition(); lasPosition = getLastVisiblePosition(); } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { // TODO Auto-generated method stub } }; super.setOnScrollListener(l); } private void inChild(int action) { setCoordinates(); for (int i = 0; i < listCoordinates.size(); i++) { System.err.println("size"+listCoordinates.size()); Coordinates coordinates = listCoordinates.get(i); int topPosition = coordinates.getTop(); System.err.println("coordinates.getTop()"+coordinates.getTop()); System.err.println("coordinates.getBottom()"+coordinates.getBottom()); int bottomPosition = coordinates.getBottom(); int bottomMoveViewPosition = DnDAdapter.emptyView.getBottom(); if (i != 0) { if (bottomMoveViewPosition > topPosition && bottomMoveViewPosition < bottomPosition) { Log.v(getClass().toString(),"Move view in position: " + i); DnDAdapter.removeEmptyEntry(); DnDAdapter.addEmptyEntry(getFirstVisiblePosition() + i); if (action == MotionEvent.ACTION_UP) { DnDAdapter.removeEmptyEntry(); DnDAdapter.addEntry(getFirstVisiblePosition() + i); } } } } } private void setCoordinates() { listCoordinates = new ArrayList<Coordinates>(); int count = getChildCount(); System.err.println("count"+count); for (int i = 0; i < count; i++) { View child = getChildAt(i); if (child != null) { Coordinates coord = new Coordinates(); coord.setTop(child.getTop()); coord.setBottom(child.getBottom()); listCoordinates.add(coord); } } } class Coordinates { private int top = 0; private int bottom = 0; public int getTop() { return top; } public void setTop(int top) { this.top = top; } public int getBottom() { return bottom; } public void setBottom(int bottom) { this.bottom = bottom; } } }
//ReorderAdapter.java: import java.util.ArrayList; import java.util.List; import com.myself.dragndrop.R; import android.content.Context; import android.graphics.Color; import android.util.Log; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.View.OnTouchListener; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; public class ReorderAdapter extends BaseAdapter { private static List<Entry> items = null; private Context context = null; public static View emptyView = null; private static Entry emptyEntry = new Entry(); public ReorderAdapter(Context context) { // TODO Auto-generated constructor stub this.context = context; // buildList(); } public List<Entry> getItems() { return items; } public void setList(List<Entry> items) { this.items = items; } @Override public int getCount() { // TODO Auto-generated method stub System.err.println("items.size()"+items.size()); return items.size(); } @Override public Object getItem(int position) { // TODO Auto-generated method stub return items.get(position); } @Override public long getItemId(int position) { // TODO Auto-generated method stub return 0; } @Override public View getView(final int position, View convertView, ViewGroup parent) { // TODO Auto-generated method stub Entry entry = items.get(position); System.err.println("getview"+position); LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); final View view = inflater.inflate(R.layout.listitem, parent, false); TextView txt = (TextView)view.findViewById(R.id.TextView01); txt.setText(entry.getName()); txt.setTextColor(Color.WHITE); final ImageView img = (ImageView)view.findViewById(R.id.entryIcon); img.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { // TODO Auto-generated method stub Log.v(getClass().toString(),"Icon onTouch. Selected position: " + position); DragAndDrop.listView.moveEntry = items.get(position); buildEmptyView(DragAndDrop.listView.moveEntry); items.remove(position); items.add(position, emptyEntry); DragAndDrop.listView.invalidateViews(); DragAndDrop.listView.setEnabled(false); DragAndDrop.listView.isMoveFlag = true; DragAndDrop.listView.moveView = view; DragAndDrop.listView.movedPosition = position; return false; } }); if (entry.getName().equals("Empty entry")) { img.setVisibility(View.INVISIBLE); txt.setVisibility(View.INVISIBLE); } return view; } private void buildEmptyView(Entry moveentry) { LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); emptyView = inflater.inflate(R.layout.emptyview, null, false); TextView txt = (TextView)emptyView.findViewById(R.id.TextView01); txt.setText(moveentry.getName()); txt.setTextColor(Color.WHITE); } public static void addEntry(int pos) { items.add(pos, DragAndDrop.listView.moveEntry); DragAndDrop.listView.invalidateViews(); } public static void addEmptyEntry(int pos) { items.add(pos, emptyEntry); DragAndDrop.listView.invalidateViews(); } public static void removeEmptyEntry() { items.remove(emptyEntry); DragAndDrop.listView.invalidateViews(); } }
//DragAndDrop.java : import java.util.ArrayList; import java.util.List; import android.app.Activity; import android.app.ListActivity; import android.content.Context; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.widget.Button; import android.widget.LinearLayout; import android.widget.ScrollView; import android.widget.TextView; public class DragAndDrop extends ListActivity { /** Called when the activity is first created. */ public static LinearLayout layout = null; public static ScrollView scrollView = null; public static CustomListView listView = null; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); ReorderAdapter adapter = new ReorderAdapter(this); adapter.setList(buildList()); listView = (CustomListView)getListView(); listView.setAdapter(adapter); } private List<Entry> buildList() { List<Entry> items = new ArrayList<Entry>(); for (int i = 0; i < 30; i++) { Entry entry = new Entry(); entry.setName("Demo entry " + i); items.add(entry); } return items; } }