Monday, January 19, 2015

Drag and Drop between ListView and GridView

Previous example show how to implement Drag-and-Drop between ListViews. As both ListView and Gridiew subclasses of AbsListView, it's easy to implement Drag-and-Drop between ListView and GridView.


Refactory LinearLayoutListView.java to LinearLayoutAbsListView.java, to implement our custom LinearLayout associate with AbsListView, for ListView or GridView.
package com.example.androidimageviewlist;

import android.content.Context;
import android.util.AttributeSet;
import android.widget.AbsListView;
import android.widget.LinearLayout;

public class LinearLayoutAbsListView extends LinearLayout {
 
 AbsListView absListView;

 public LinearLayoutAbsListView(Context context) {
  super(context);
  // TODO Auto-generated constructor stub
 }

 public LinearLayoutAbsListView(Context context, AttributeSet attrs) {
  super(context, attrs);
  // TODO Auto-generated constructor stub
 }

 public LinearLayoutAbsListView(Context context, AttributeSet attrs,
   int defStyleAttr) {
  super(context, attrs, defStyleAttr);
  // TODO Auto-generated constructor stub
 }

 public void setAbsListView(AbsListView alv){
  absListView = alv;
 }

}

Create /res/layout/gridrow.xml to define row layout for GridView.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="horizontal" >

    <ImageView
        android:id="@+id/gridrowImageView"
        android:layout_gravity="center"
        android:layout_width="48dp"
        android:layout_height="48dp" />

</LinearLayout>

Modify /res/layout/activity_main.xml to include three <com.example.androidimageviewlist.LinearLayoutAbsListView>
<LinearLayout 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"
    android:orientation="vertical"
    android:padding="4dp"
    tools:context="com.example.androidimageviewlist.MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="2"
        android:background="@android:color/background_dark"
        android:orientation="horizontal" >

        <com.example.androidimageviewlist.LinearLayoutAbsListView
            android:id="@+id/pane1"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_margin="4dp"
            android:layout_weight="1"
            android:background="@android:color/background_light"
            android:orientation="vertical" >

            <ListView
                android:id="@+id/listview1"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />
        </com.example.androidimageviewlist.LinearLayoutAbsListView>

        <com.example.androidimageviewlist.LinearLayoutAbsListView
            android:id="@+id/pane2"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_margin="4dp"
            android:layout_weight="1"
            android:background="@android:color/background_light"
            android:orientation="vertical" >

            <ListView
                android:id="@+id/listview2"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />
        </com.example.androidimageviewlist.LinearLayoutAbsListView>
        
        <com.example.androidimageviewlist.LinearLayoutAbsListView
            android:id="@+id/pane3"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_margin="4dp"
            android:layout_weight="1"
            android:background="@android:color/background_light"
            android:orientation="vertical" >

            <GridView
                android:id="@+id/gridview3"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:numColumns="auto_fit"
                android:verticalSpacing="10dp"
                android:horizontalSpacing="10dp"
                android:columnWidth="60dp"
                android:stretchMode="columnWidth"
                android:gravity="center" />
        </com.example.androidimageviewlist.LinearLayoutAbsListView>
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:orientation="horizontal" >

        <TextView
            android:id="@+id/prompt"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@android:color/black"
            android:gravity="bottom"
            android:textColor="@android:color/white" />
    </LinearLayout>

</LinearLayout>

MainActivity.java
package com.example.androidimageviewlist;

import java.util.ArrayList;
import java.util.List;

import android.support.v7.app.ActionBarActivity;
import android.text.method.ScrollingMovementMethod;
import android.app.Activity;
import android.content.ClipData;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.view.DragEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.DragShadowBuilder;
import android.view.View.OnDragListener;
import android.view.View.OnLongClickListener;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.BaseAdapter;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends ActionBarActivity {

 //items stored in ListView
 public class Item {
  Drawable ItemDrawable;
  String ItemString;
  Item(Drawable drawable, String t){
   ItemDrawable = drawable;
   ItemString = t;
  }
 }
 
 //objects passed in Drag and Drop operation
 class PassObject{
  View view;
  Item item;
  List<Item> srcList;
  
  PassObject(View v, Item i, List<Item> s){
   view = v;
   item = i;
   srcList = s;
  }
 }
 
 static class ViewHolder {
  ImageView icon;
  TextView text; 
 }
 
 static class GridViewHolder {
  ImageView icon; 
 }
 
 public class ItemBaseAdapter extends BaseAdapter {

  Context context;
  List<Item> list;

  ItemBaseAdapter(Context c, List<Item> l){
   context = c;
   list = l;
  }

  @Override
  public int getCount() {
   return list.size();
  }

  @Override
  public Object getItem(int position) {
   return list.get(position);
  }

  @Override
  public long getItemId(int position) {
   return position;
  }
  
  public List<Item> getList(){
   return list;
  }

  @Override
  public View getView(int position, View convertView, ViewGroup parent) {
   // TODO Auto-generated method stub
   return null;
  }
  
 }
 

 public class ItemListAdapter extends ItemBaseAdapter {
  
  ItemListAdapter(Context c, List<Item> l) {
   super(c, l);
  }

  @Override
  public View getView(int position, View convertView, ViewGroup parent) {
   View rowView = convertView;
   
      // reuse views
      if (rowView == null) {
       LayoutInflater inflater = ((Activity) context).getLayoutInflater();
       rowView = inflater.inflate(R.layout.row, null);

       ViewHolder viewHolder = new ViewHolder();
       viewHolder.icon = (ImageView) rowView.findViewById(R.id.rowImageView);
       viewHolder.text = (TextView) rowView.findViewById(R.id.rowTextView);
       rowView.setTag(viewHolder); 
      }

      ViewHolder holder = (ViewHolder) rowView.getTag();
      holder.icon.setImageDrawable(list.get(position).ItemDrawable);
      holder.text.setText(list.get(position).ItemString);
      
      rowView.setOnDragListener(new ItemOnDragListener(list.get(position)));

      return rowView;
  }

 }
 
 public class ItemGridAdapter extends ItemBaseAdapter {

  ItemGridAdapter(Context c, List<Item> l) {
   super(c, l);
  }
  
  @Override
  public View getView(int position, View convertView, ViewGroup parent) {
   View gridrowView = convertView;
   
      // reuse views
      if (gridrowView == null) {
       LayoutInflater inflater = ((Activity) context).getLayoutInflater();
       gridrowView = inflater.inflate(R.layout.gridrow, null);

       GridViewHolder gridviewHolder = new GridViewHolder();
       gridviewHolder.icon = (ImageView) gridrowView.findViewById(R.id.gridrowImageView);
       gridrowView.setTag(gridviewHolder); 
      }

      GridViewHolder holder = (GridViewHolder) gridrowView.getTag();
      holder.icon.setImageDrawable(list.get(position).ItemDrawable);

      gridrowView.setOnDragListener(new ItemOnDragListener(list.get(position)));

      return gridrowView;
  }
  
 }

 List<Item> items1, items2, items3;
 ListView listView1, listView2;
 GridView gridView3;
 ItemListAdapter myItemListAdapter1, myItemListAdapter2;
 ItemGridAdapter myItemGridAdapter3;
 LinearLayoutAbsListView area1, area2, area3;
 TextView prompt;
 
 //Used to resume original color in drop ended/exited
 int resumeColor;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  listView1 = (ListView)findViewById(R.id.listview1);
  listView2 = (ListView)findViewById(R.id.listview2);
  gridView3 = (GridView)findViewById(R.id.gridview3);
  
  area1 = (LinearLayoutAbsListView)findViewById(R.id.pane1);
  area2 = (LinearLayoutAbsListView)findViewById(R.id.pane2);
  area3 = (LinearLayoutAbsListView)findViewById(R.id.pane3);
  area1.setOnDragListener(myOnDragListener);
  area2.setOnDragListener(myOnDragListener);
  area3.setOnDragListener(myOnDragListener);
  area1.setAbsListView(listView1);
  area2.setAbsListView(listView2);
  area3.setAbsListView(gridView3);
  
  initItems();
  myItemListAdapter1 = new ItemListAdapter(this, items1);
  myItemListAdapter2 = new ItemListAdapter(this, items2);
  myItemGridAdapter3 = new ItemGridAdapter(this, items3);
  listView1.setAdapter(myItemListAdapter1);
  listView2.setAdapter(myItemListAdapter2);
  gridView3.setAdapter(myItemGridAdapter3);
  
  listView1.setOnItemClickListener(listOnItemClickListener);
  listView2.setOnItemClickListener(listOnItemClickListener);
  gridView3.setOnItemClickListener(listOnItemClickListener);
  
  listView1.setOnItemLongClickListener(myOnItemLongClickListener);
  listView2.setOnItemLongClickListener(myOnItemLongClickListener);
  gridView3.setOnItemLongClickListener(myOnItemLongClickListener);
  
  prompt = (TextView) findViewById(R.id.prompt);
  // make TextView scrollable
  prompt.setMovementMethod(new ScrollingMovementMethod());
  //clear prompt area if LongClick
  prompt.setOnLongClickListener(new OnLongClickListener(){
   
   @Override
   public boolean onLongClick(View v) {
    prompt.setText("");
    return true; 
   }});
  
  resumeColor  = getResources().getColor(android.R.color.background_light);

 }
 
 OnItemLongClickListener myOnItemLongClickListener = new OnItemLongClickListener(){

  @Override
  public boolean onItemLongClick(AdapterView<?> parent, View view,
    int position, long id) {
   Item selectedItem = (Item)(parent.getItemAtPosition(position));
   
   ItemBaseAdapter associatedAdapter = (ItemBaseAdapter)(parent.getAdapter());
      List<Item> associatedList = associatedAdapter.getList();
   
   PassObject passObj = new PassObject(view, selectedItem, associatedList);

   ClipData data = ClipData.newPlainText("", "");
   DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(view);
   view.startDrag(data, shadowBuilder, passObj, 0);
   
   return true;
  }
  
 };
 
 OnDragListener myOnDragListener = new OnDragListener() {

  @Override
  public boolean onDrag(View v, DragEvent event) {
   String area;
   if(v == area1){
    area = "area1"; 
   }else if(v == area2){
    area = "area2"; 
   }else if(v == area3){
    area = "area3"; 
   }else{
    area = "unknown"; 
   }
   
   switch (event.getAction()) {
    case DragEvent.ACTION_DRAG_STARTED:
     prompt.append("ACTION_DRAG_STARTED: " + area  + "\n");
     break; 
    case DragEvent.ACTION_DRAG_ENTERED:
     prompt.append("ACTION_DRAG_ENTERED: " + area  + "\n");
     break; 
    case DragEvent.ACTION_DRAG_EXITED:
     prompt.append("ACTION_DRAG_EXITED: " + area  + "\n");
     break; 
    case DragEvent.ACTION_DROP:
     prompt.append("ACTION_DROP: " + area  + "\n");

     PassObject passObj = (PassObject)event.getLocalState();
     View view = passObj.view;
     Item passedItem = passObj.item;
     List<Item> srcList = passObj.srcList;
     AbsListView oldParent = (AbsListView)view.getParent();
     ItemBaseAdapter srcAdapter = (ItemBaseAdapter)(oldParent.getAdapter());
     
     LinearLayoutAbsListView newParent = (LinearLayoutAbsListView)v;
     ItemBaseAdapter destAdapter = (ItemBaseAdapter)(newParent.absListView.getAdapter());
        List<Item> destList = destAdapter.getList();
     
     if(removeItemToList(srcList, passedItem)){
      addItemToList(destList, passedItem);
     }
     
     srcAdapter.notifyDataSetChanged();
     destAdapter.notifyDataSetChanged();
     
     //smooth scroll to bottom
     newParent.absListView.smoothScrollToPosition(destAdapter.getCount()-1);
     
     break;
      case DragEvent.ACTION_DRAG_ENDED:
       prompt.append("ACTION_DRAG_ENDED: " + area  + "\n");  
      default:
       break;    
   }
      
   return true;
  }
  
 };
 
 class ItemOnDragListener implements OnDragListener{
  
  Item  me;
  
  ItemOnDragListener(Item i){
   me = i;
  }

  @Override
  public boolean onDrag(View v, DragEvent event) {
   switch (event.getAction()) {
   case DragEvent.ACTION_DRAG_STARTED:
    prompt.append("Item ACTION_DRAG_STARTED: " + "\n");
    break; 
   case DragEvent.ACTION_DRAG_ENTERED:
    prompt.append("Item ACTION_DRAG_ENTERED: " + "\n");
    v.setBackgroundColor(0x30000000);
    break; 
   case DragEvent.ACTION_DRAG_EXITED:
    prompt.append("Item ACTION_DRAG_EXITED: " + "\n");
    v.setBackgroundColor(resumeColor);
    break; 
   case DragEvent.ACTION_DROP:
    prompt.append("Item ACTION_DROP: " + "\n");

    PassObject passObj = (PassObject)event.getLocalState();
    View view = passObj.view;
    Item passedItem = passObj.item;
    List<Item> srcList = passObj.srcList;
    AbsListView oldParent = (AbsListView)view.getParent();
    ItemBaseAdapter srcAdapter = (ItemBaseAdapter)(oldParent.getAdapter());
    
    AbsListView newParent = (AbsListView)v.getParent();
    ItemBaseAdapter destAdapter = (ItemBaseAdapter)(newParent.getAdapter());
    List<Item> destList = destAdapter.getList();
    
    int removeLocation = srcList.indexOf(passedItem);
    int insertLocation = destList.indexOf(me);
    /*
     * If drag and drop on the same list, same position,
     * ignore
     */
    if(srcList != destList || removeLocation != insertLocation){
     if(removeItemToList(srcList, passedItem)){
      destList.add(insertLocation, passedItem);
     }
     
     srcAdapter.notifyDataSetChanged();
     destAdapter.notifyDataSetChanged();
    }

    v.setBackgroundColor(resumeColor);
    
    break;
     case DragEvent.ACTION_DRAG_ENDED:
      prompt.append("Item ACTION_DRAG_ENDED: "  + "\n");
      v.setBackgroundColor(resumeColor);
     default:
      break;    
  }
     
  return true;
  }
  
 }
 
 OnItemClickListener listOnItemClickListener = new OnItemClickListener(){

  @Override
  public void onItemClick(AdapterView<?> parent, View view, int position,
    long id) {
   Toast.makeText(MainActivity.this, 
     ((Item)(parent.getItemAtPosition(position))).ItemString, 
     Toast.LENGTH_SHORT).show();
  }
  
 };

 private void initItems(){
  items1 = new ArrayList<Item>();
  items2 = new ArrayList<Item>();
  items3 = new ArrayList<Item>();
  
  TypedArray arrayDrawable = getResources().obtainTypedArray(R.array.resicon);
  TypedArray arrayText = getResources().obtainTypedArray(R.array.restext);
  
  for(int i=0; i<arrayDrawable.length(); i++){
   Drawable d = arrayDrawable.getDrawable(i);
   String s = arrayText.getString(i);
   Item item = new Item(d, s);
   items1.add(item);
  }
  
  arrayDrawable.recycle();
  arrayText.recycle();
 }
 
 private boolean removeItemToList(List<Item> l, Item it){
  boolean result = l.remove(it);
  return result;
 }
 
 private boolean addItemToList(List<Item> l, Item it){
  boolean result = l.add(it);
  return result;
 }

}

download filesDownload the files.

1 comment:

M. Ridwan H.D.P said...

Why when i drop an item from area 3 to other area the program has stopped?
In last post it Grid View for area3,and in this post is listview.