DragDropManager.class
package com.example.dragdrop;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import android.annotation.TargetApi;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.os.Build;
import android.view.ActionMode;
import android.view.ActionMode.Callback;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.view.accessibility.AccessibilityEvent;
import android.widget.ImageView;
import android.widget.PopupWindow;
public class DragDropManager
{
private static DragDropManager instance;
private Activity mActivity;
private List<View> dropzones;
private Map<View, Integer> dropzonestates;
private Map<View, DropZoneListener> dropzonelisteners;
private PopupWindow popoup;
private MotionEvent firstEvent;
private Rect rect;
private Object item;
public static DragDropManager getInstance()
{
if (instance == null) instance = new DragDropManager();
return instance;
}
private DragDropManager()
{
}
public void init(Activity a)
{
mActivity = a;
dropzones = new ArrayList<View>();
dropzonelisteners = new HashMap<View, DropZoneListener>();
dropzonestates = new HashMap<View, Integer>();
rect = new Rect();
}
public void addDropZone(View zone, DropZoneListener zonelistener)
{
dropzones.add(zone);
dropzonelisteners.put(zone, zonelistener);
dropzonestates.put(zone, 0);
}
public void clearZones()
{
dropzones.clear();
dropzonelisteners.clear();
dropzonestates.clear();
}
public void clearZone(View zone)
{
dropzones.remove(zone);
dropzonelisteners.remove(zone);
dropzonestates.remove(zone);
}
private void checkDropZones(MotionEvent event)
{
boolean isOver;
HashSet<DropZoneListener> listeners = new HashSet<DropZoneListener>(dropzonelisteners.values());
for (View zone : dropzones)
{
int[] location = new int[2];
zone.getLocationInWindow(location);
zone.getDrawingRect(rect);
rect.offset(location[0], location[1]);
isOver = rect.contains((int) event.getRawX(), (int) event.getRawY());
switch (dropzonestates.get(zone))
{
case 0:
if (isOver)
{
for(DropZoneListener listener:listeners)
{
listener.OnDragZoneEntered(zone, item);
}
dropzonestates.put(zone, 1);
}
break;
case 1:
if (!isOver)
{
for(DropZoneListener listener:listeners)
{
listener.OnDragZoneLeft(zone, item);
}
dropzonestates.put(zone, 0);
}
else if (isOver && event.getAction()==MotionEvent.ACTION_UP)
{
for(DropZoneListener listener:listeners)
{
listener.OnDropped(zone, item);
}
dropzonestates.put(zone, 0);
}
break;
}
}
}
public void startDragging(final View dragView, Object item)
{
this.item = item;
// Copy view Bitmap (Clone Object visual)
ImageView view = new ImageView(mActivity);
view.measure(dragView.getWidth(), dragView.getHeight());
Bitmap returnedBitmap = Bitmap.createBitmap(dragView.getWidth(), dragView.getHeight(),Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(returnedBitmap);
dragView.draw(canvas);
view.setBackgroundDrawable(new BitmapDrawable(dragView.getResources(), returnedBitmap));
// Set up Window
popoup = new PopupWindow(view, dragView.getWidth(), dragView.getHeight());
popoup.setWindowLayoutMode(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
// set window at position
int[] location = new int[2];
dragView.getLocationInWindow(location);
popoup.showAtLocation(mActivity.getWindow().getDecorView(), Gravity.NO_GRAVITY, location[0], location[1]);
// Switch call Backs
callbackDefault = mActivity.getWindow().getCallback();
mActivity.getWindow().setCallback(callback);
}
private android.view.Window.Callback callbackDefault;
private android.view.Window.Callback callback = new android.view.Window.Callback()
{
@Override
public boolean dispatchGenericMotionEvent(MotionEvent event)
{
// TODO Auto-generated method stub
return false;
}
@Override
public boolean dispatchKeyEvent(KeyEvent event)
{
// TODO Auto-generated method stub
return false;
}
@Override
public boolean dispatchKeyShortcutEvent(KeyEvent event)
{
// TODO Auto-generated method stub
return false;
}
@Override
public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event)
{
// TODO Auto-generated method stub
return false;
}
@Override
public boolean dispatchTouchEvent(MotionEvent event)
{
checkDropZones(event);
if (event.getAction() == MotionEvent.ACTION_DOWN)
{
// popoup.update((int)event.getRawX(), (int)event.getRawY(), -1,
// -1);
}
if (event.getAction() == MotionEvent.ACTION_MOVE)
{
if (firstEvent == null) firstEvent = MotionEvent.obtain(event);
// Log.v("EVENT","X:"+event.getRawX() + " _X:" + location[0] +
// " __X:" + firstEvent.getRawX());
// Log.v("EVENT","Y:"+event.getRawY() + " _Y:" + location[1] +
// " __Y:" + firstEvent.getRawY());
float pos_x = event.getRawX() + (-popoup.getWidth() / 2);
float pos_y = event.getRawY() + (-popoup.getHeight() / 2);
popoup.update((int) pos_x, (int) pos_y, -1, -1);
}
if (event.getAction() == MotionEvent.ACTION_UP)
{
popoup.dismiss();
mActivity.getWindow().setCallback(callbackDefault);
}
return false;
}
@Override
public boolean dispatchTrackballEvent(MotionEvent event)
{
return false;
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
@Override
public void onActionModeFinished(ActionMode mode)
{
// TODO Auto-generated method stub
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
@Override
public void onActionModeStarted(ActionMode mode)
{
// TODO Auto-generated method stub
}
@Override
public void onAttachedToWindow()
{
// TODO Auto-generated method stub
}
@Override
public void onContentChanged()
{
// TODO Auto-generated method stub
}
@Override
public boolean onCreatePanelMenu(int featureId, Menu menu)
{
// TODO Auto-generated method stub
return false;
}
@Override
public View onCreatePanelView(int featureId)
{
// TODO Auto-generated method stub
return null;
}
@Override
public void onDetachedFromWindow()
{
// TODO Auto-generated method stub
}
@Override
public boolean onMenuItemSelected(int featureId, MenuItem item)
{
// TODO Auto-generated method stub
return false;
}
@Override
public boolean onMenuOpened(int featureId, Menu menu)
{
// TODO Auto-generated method stub
return false;
}
@Override
public void onPanelClosed(int featureId, Menu menu)
{
// TODO Auto-generated method stub
}
@Override
public boolean onPreparePanel(int featureId, View view, Menu menu)
{
// TODO Auto-generated method stub
return false;
}
@Override
public boolean onSearchRequested()
{
// TODO Auto-generated method stub
return false;
}
@Override
public void onWindowAttributesChanged(android.view.WindowManager.LayoutParams attrs)
{
// TODO Auto-generated method stub
}
@Override
public void onWindowFocusChanged(boolean hasFocus)
{
// TODO Auto-generated method stub
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
@Override
public ActionMode onWindowStartingActionMode(Callback callback)
{
// TODO Auto-generated method stub
return null;
}
};
public interface DropZoneListener
{
void OnDragZoneEntered(View zone, Object item);
void OnDragZoneLeft(View zone, Object item);
void OnDropped(View zone, Object item);
}
}
MainActivity.class
package com.example.dragdrop;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnLongClickListener;
import android.view.View.OnTouchListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import com.example.dragdrop.DragDropManager.DropZoneListener;
public class MainActivity extends Activity implements OnLongClickListener, OnTouchListener
{
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DragDropManager.getInstance().init(this);
Button b1 = (Button) findViewById(R.id.button1);
Button b2 = (Button) findViewById(R.id.button2);
Button b3 = (Button) findViewById(R.id.button3);
EditText et1 = (EditText) findViewById(R.id.editText1);
TextView tv1 = (TextView) findViewById(R.id.textView1);
Button b4 = (Button) findViewById(R.id.button4);
Button b5 = (Button) findViewById(R.id.button5);
Button b6 = (Button) findViewById(R.id.button6);
b1.setOnTouchListener(this);
b2.setOnLongClickListener(this);
b3.setOnTouchListener(this);
et1.setOnTouchListener(this);
tv1.setOnTouchListener(this);
DragDropManager.getInstance().addDropZone(b4, dropZoneListener1);
DragDropManager.getInstance().addDropZone(b5, dropZoneListener1);
DragDropManager.getInstance().addDropZone(b6, dropZoneListener1);
}
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
DropZoneListener dropZoneListener1 = new DropZoneListener()
{
@Override
public void OnDropped(View zone, Object item)
{
Log.v("ddddd","drop time");
switch(zone.getId())
{
case R.id.button4:
if (item instanceof String)
((Button)zone).setText("DROP ITEM OK");
else
((Button)zone).setText("DROP ITEM ERR");
break;
case R.id.button5:
((Button)zone).setText("DROP");
break;
case R.id.button6:
if (item instanceof Integer)
((Button)zone).setText("DROP ITEM OK");
else
((Button)zone).setText("DROP ITEM ERR");
break;
}
}
@Override
public void OnDragZoneLeft(View zone, Object item)
{
switch(zone.getId())
{
case R.id.button4:
((Button)zone).setText("LEFT");
break;
case R.id.button5:
((Button)zone).setText("LEFT");
break;
case R.id.button6:
((Button)zone).setText("LEFT");
break;
}
}
@Override
public void OnDragZoneEntered(View zone, Object item)
{
switch(zone.getId())
{
case R.id.button4:
if (item instanceof String)
((Button)zone).setText("ENTER ITEM OK");
else
((Button)zone).setText("ENTER ITEM ERR");
break;
case R.id.button5:
((Button)zone).setText("ENTER");
break;
case R.id.button6:
if (item instanceof Integer)
((Button)zone).setText("ENTER ITEM OK");
else
((Button)zone).setText("ENTER ITEM ERR");
break;
}
}
};
@Override
public boolean onLongClick(View v)
{
DragDropManager.getInstance().startDragging(v, 0);
return false;
}
@Override
public boolean onTouch(View v, MotionEvent event)
{
DragDropManager.getInstance().startDragging(v, "String");
return false;
}
}
activity_main.xml
<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" >
<Button
android:id="@+id/button1"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="14dp"
android:text="Click" />
<Button
android:id="@+id/button2"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_alignLeft="@+id/button1"
android:layout_below="@+id/button1"
android:layout_marginTop="29dp"
android:text="Long" />
<Button
android:id="@+id/button3"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_alignLeft="@+id/button2"
android:layout_below="@+id/button2"
android:layout_marginTop="16dp"
android:text="Click" />
<Button
android:id="@+id/button6"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_alignTop="@+id/button3"
android:layout_marginLeft="39dp"
android:layout_toRightOf="@+id/button3"
android:text="Drop3" />
<Button
android:id="@+id/button5"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_alignLeft="@+id/button4"
android:layout_centerVertical="true"
android:text="Drop2" />
<Button
android:id="@+id/button4"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_above="@+id/button5"
android:layout_alignParentRight="true"
android:layout_marginBottom="35dp"
android:layout_marginRight="20dp"
android:text="Drop1" />
<EditText
android:id="@+id/editText1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/button3"
android:layout_below="@+id/button3"
android:layout_marginTop="17dp"
android:ems="10" >
<requestFocus />
</EditText>
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/button6"
android:layout_alignParentLeft="true"
android:text="Large Text"
android:textAppearance="?android:attr/textAppearanceLarge" />
</RelativeLayout>
У меня есть вдохновение от MobileAnarchyWidget, но я кое-что улучшаю.
Как вы можете видеть, я использую PopupWindow для создания dragEfect, даже когда я клонирую визуальную часть из перетаскиваемого объекта. Также мне не нужно использовать какую-либо часть макета. Просто поместите DragDropManager.class в ваш проект. Никаких изменений не требуется. Никаких дополнительных ресурсов. Больше зон может быть поражено одновременно, если одна зона полностью / частично покрывает другую. Вы можете перетащить все, что хотя бы на вид. Я переключаю функцию обратного вызова в окне «Активность», чтобы при перетаскивании чего-либо еще не было доступа к событиям. В этом решении вы никогда не теряете фокус из Draggable, а также когда вы поднимаете палец вверх на экране, DragDrop автоматически завершается (активность восстанавливает контроль над обратными вызовами).
У меня нет времени, чтобы показать вам все комбинации для использования. Но, как вы можете видеть, есть
только один DropZoneListener. Вы можете использовать больше, но помните, что все слушатели вызываются, и все измененные состояния перетаскивания отправляются каждому слушателю.
пример:
Дропзоны D1, D2;
Слушатель L1, L2;
если D1 или D2 изменились
L1 (Dx) и L2 (Dx)
если D1 и D2 изменились
L1 (D1, D2) и L2 (D1, D2)
Но это хорошо, потому что вы знаете, если оно упало где-то еще. И я забываю, что DragItem - это Object, поэтому при удалении вы должны разрешить тип объекта. Но это также хорошо, потому что при использовании фрагментов вы никогда не знаете, какие данные можно перетаскивать.
В моем решении я проверяю на уровне типа объекта. Если объект не поддерживается dragzone, вы узнаете.