This is how I do it in my app:
For the "view" that you want to drag, set this in the onTouchListener:
public final class ChoiceTouchListener implements OnTouchListener {
Context context;
//int index;
public static float offsetX = 0,offsetY = 0;
DragShadowBuilder shadowBuilder;
public ChoiceTouchListener(Context context) {
super();
this.context = context;
//this.index = index;
}
public boolean onTouch(View view, MotionEvent motionEvent) {
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
//view.setTag("option"+index);
ClipData data = ClipData.newPlainText("tag", view.getTag().toString());
shadowBuilder = new View.DragShadowBuilder(view);
//start dragging the item touched
view.startDrag(data, shadowBuilder, view, 0);
offsetX = view.getLeft();//(int)view.getX();//(int)motionEvent.getX();
offsetY = view.getTop();//(int)view.getY();//motionEvent.getY();
view.setVisibility(View.INVISIBLE);
Log.v("here","it is ::" + (int)motionEvent.getX() + " , "+(int)motionEvent.getY());
return false;
}
return true;
}
}
And here's a RelativeLayout that has the destination "view" set in the middle and listens for the drag and drop events:
public class DragLayout extends RelativeLayout {
boolean DEBUG = true;
AnimationDrawable blenderAnim;
Handler handlerAnim2;
Context context;
private int dimensionInPixel = 200;
int screenWidth,screenHeight;
public DragLayout(Context context) {
super(context);
this.context = context;
//not to include in main program
getDimensionsofScreen();
setLayout();
setViews();
}
private void setLayout() {
// set according to parent layout (not according to current layout)
RelativeLayout.LayoutParams rLp = new RelativeLayout.LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
rLp.topMargin = 2 * (screenHeight / 25); // calculating 1/10 of 4/5
// screen
this.setLayoutParams(rLp);
}
void setViews() {
ImageView img2 = new ImageView(context);
int dimensionInDp = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dimensionInPixel, getResources().getDisplayMetrics());
RelativeLayout.LayoutParams rLp = new RelativeLayout.LayoutParams(
(screenWidth / 5), (screenHeight / 5));
rLp.topMargin = (screenHeight / 10);
rLp.leftMargin = (4*screenWidth / 10);
rLp.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);
img2.setLayoutParams(rLp);
img2.getLayoutParams().height = dimensionInDp;
img2.getLayoutParams().width = dimensionInDp;
img2.setImageDrawable(getResources().getDrawable(R.drawable.blender_anim));
img2.setOnDragListener(new ChoiceDragListener(context));
this.addView(img2);
blenderAnim = (AnimationDrawable)img2.getDrawable();
blenderAnim.setOneShot(true);
blenderAnim.stop();
}
public ArrayList<Integer> getDimensionsofScreen() {
//metrics that holds the value of height and width
DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();;
ArrayList<Integer> vals = new ArrayList<Integer>();
vals.add(displayMetrics.widthPixels);
vals.add(displayMetrics.heightPixels);
screenHeight = displayMetrics.heightPixels;
screenWidth = displayMetrics.widthPixels;
return vals;
}
@SuppressLint("NewApi")
@Override
public boolean onDragEvent(DragEvent event) {
int mCurX = (int) event.getX();
int mCurY = (int) event.getY();
if(event.getAction() == DragEvent.ACTION_DRAG_STARTED || event.getAction() == DragEvent.ACTION_DRAG_ENTERED) {
if (blenderAnim.isRunning()) {
blenderAnim.stop();
} else {
blenderAnim.run();
handlerAnim2 = new Handler();
handlerAnim2.postDelayed(
new Runnable(){
@Override
public void run() {
blenderAnim.stop();
}},
getAnimationDuration(blenderAnim));
}
}
if(event.getAction() == DragEvent.ACTION_DROP || event.getAction() == DragEvent.ACTION_DRAG_EXITED) {
if (blenderAnim.isRunning()) {
blenderAnim.stop();
} else {
blenderAnim.run();
handlerAnim2 = new Handler();
handlerAnim2.postDelayed(
new Runnable(){
@Override
public void run() {
blenderAnim.stop();
}},
getAnimationDuration(blenderAnim));
}
Log.v("here", "it is :: " + mCurX + ", " + mCurY);
View view1 = (View) event.getLocalState();
view1.setVisibility(View.VISIBLE);
ObjectAnimator animationx = ObjectAnimator.ofFloat(view1,"translationX", mCurX - ChoiceTouchListener.offsetX-(screenWidth / 10),0.0f);
ObjectAnimator animationy = ObjectAnimator.ofFloat(view1, "translationY", mCurY - ChoiceTouchListener.offsetY - (screenHeight / 10), 0.0f);
AnimatorSet animSet = new AnimatorSet();
animSet.setDuration(500);
animSet.playTogether(animationx,animationy);
animSet.start();
}
if(event.getAction() == DragEvent.ACTION_DROP || event.getAction() == DragEvent.ACTION_DRAG_ENDED){
if(blenderAnim.isRunning()){
blenderAnim.stop();
}
}
return true;
}
private int getAnimationDuration(AnimationDrawable src){
int dur = 0;
for(int i=0; i<src.getNumberOfFrames(); i++){
dur += src.getDuration(i);
}
return dur;
}
}
This is the drag listener for the ImageView in the DragLayout:
public class ChoiceDragListener implements View.OnDragListener {
boolean DEBUG = true;
Context context;
public String TAG = "Drag Layout:";
public ChoiceDragListener(Context context){
this.context = context;
}
@Override
public boolean onDrag(View v, DragEvent event) {
switch (event.getAction()) {
case DragEvent.ACTION_DRAG_STARTED:
if(DEBUG) Log.v("here","drag started");
break;
case DragEvent.ACTION_DRAG_ENTERED:
break;
case DragEvent.ACTION_DRAG_LOCATION:
int mCurX = (int) event.getX();
int mCurY = (int) event.getY();
if(DEBUG) Log.v("Cur(X, Y) : " ,"here ::" + mCurX + ", " + mCurY );
break;
case DragEvent.ACTION_DRAG_EXITED:
if(DEBUG)
Log.v("here","drag exits");
break;
case DragEvent.ACTION_DROP:
//handle the dragged view being dropped over a drop view
View view = (View) event.getLocalState();
ClipData cd = event.getClipData();
ClipData.Item item = cd.getItemAt(0);
String resp = item.coerceToText(context).toString();
//view dragged item is being dropped on
ImageView dropTarget = (ImageView) v;
//view being dragged and dropped
final ImageView dropped = (ImageView) view;
dropped.setEnabled(false);
//if an item has already been dropped here, there will be a tag
final Object tag = dropTarget.getTag();
LayoutInflater li = LayoutInflater.from(context);
View promptsView = li.inflate(R.layout.ns_scoop_dialog, null);
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(
context);
// set prompts.xml to alertdialog builder
alertDialogBuilder.setView(promptsView);
final EditText userInput = (EditText) promptsView
.findViewById(R.id.edit1);
// set dialog message
alertDialogBuilder
.setIcon(R.mipmap.ic_launcher)
.setTitle(dropped.getTag().toString())
.setCancelable(false)
.setPositiveButton("OK",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,int id) {
// get user input and set it to result
// edit text
String inAmt = userInput.getText().toString();
CreateSmoothie.nsList.add(inAmt + " Green Scoops " + dropped.getTag().toString());
Log.d(TAG, inAmt + " Green Scoops " + dropped.getTag().toString() + " added to list");
dialog.dismiss();
//dropped.setEnabled(true);
}
})
.setNegativeButton("Cancel",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
int existingID = dropped.getId();
//set the original view visible again
((Activity) context).findViewById(existingID).setVisibility(View.VISIBLE);
dropped.setEnabled(true);
}
});
// create alert dialog
AlertDialog alertDialog = alertDialogBuilder.create();
// show it
alertDialog.show();
//Button nButton = alertDialog.getButton(DialogInterface.BUTTON_NEGATIVE);
//nButton.setBackgroundColor(Color.GREEN);
//Button pButton = alertDialog.getButton(DialogInterface.BUTTON_POSITIVE);
//pButton.setBackgroundColor(Color.GREEN);
if(tag!=null)
{
//the tag is the view id already dropped here
int existingID = (Integer)tag;
//set the original view visible again
((Activity) context).findViewById(existingID).setVisibility(View.VISIBLE);
}
break;
case DragEvent.ACTION_DRAG_ENDED:
if(DEBUG) Log.i("drag event", "ended::" + ChoiceTouchListener.offsetX + "," + ChoiceTouchListener.offsetY);
/**
* returning false so that goes to parentView onDrag function
*/
return false;
//break;
default:
break;
}
return true;
}
}
Hope that helps.