I'm trying to restrict drag and drop motion to only the Y-axis so that a user can only take a view and drag it up or down--not left or right.
I've got two views (ids of textView and dropZone) right now. One (textView) has a touch listener set to it and another (dropZone) has a drag listener set on it.
Here's the layout xml (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"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<TextView
android:id="@+id/textView"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="50dp"
android:background="#FFFFFF00"
android:text="Text Drag" />
<TextView
android:id="@+id/dropZone"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="167dp"
android:background="#FFFF0000"
android:text="Drop Zone" />
</RelativeLayout>
The following is the activity code:
package com.example.dragexperiment;
import android.app.Activity;
import android.content.ClipData;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import android.view.DragEvent;
import android.view.Menu;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.DragShadowBuilder;
import android.view.View.OnDragListener;
import android.view.View.OnGenericMotionListener;
import android.view.View.OnTouchListener;
import android.widget.RelativeLayout;
import android.widget.TextView;
public class MainActivity extends Activity {
TextView tv, dz, sv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = (TextView) findViewById(R.id.textView);
dz = (TextView) findViewById(R.id.dropZone);
tv.setOnTouchListener(new MyTouchListener());
dz.setOnDragListener(new MyDragListener());
}
private final class MyTouchListener implements OnTouchListener {
int viewX0, viewY0,
cY0, cY1,
deltaCursorY;
@Override
public boolean onTouch(final View v,final MotionEvent event) {
switch(event.getAction()) {
case MotionEvent.ACTION_DOWN:
viewX0 = (int) v.getX();
viewY0 = (int) v.getY();
cY0 = (int) event.getRawY();
ClipData data = ClipData.newPlainText("", "");
DragShadowBuilder shadow = new View.DragShadowBuilder(v);
v.startDrag(data, shadow, v, 0);
return true;
case MotionEvent.ACTION_MOVE:
// cY1 = (int) event.getRawY();
// deltaCursorY = cY1 - cY0;
// v.setX(viewX0);
// v.setY(viewY0 + deltaCursorY);
return true;
}
return false;
}
}
class MyDragListener implements OnDragListener {
public boolean onDrag(View v, DragEvent event) {
switch (event.getAction()) {
case DragEvent.ACTION_DRAG_STARTED:
break;
case DragEvent.ACTION_DRAG_ENTERED:
v.setBackgroundColor(Color.BLUE);
break;
case DragEvent.ACTION_DRAG_EXITED:
break;
case DragEvent.ACTION_DROP:
v.setBackgroundColor(Color.BLUE);
break;
case DragEvent.ACTION_DRAG_ENDED:
break;
default:
break;
}
return true;
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
As you can see from the code above, when a user drags textView over dropZone, I try to turn the dropZone view background color to blue. This works fine if I use create a DragShadowBuilder in the ACTION_DOWN motion event:
ClipData data = ClipData.newPlainText("", "");
DragShadowBuilder shadow = new View.DragShadowBuilder(v);
v.startDrag(data, shadow, v, 0);
The problem is that I can't control the shadow so that it only moves along the Y-axis (vertical) axis.
If I take out the DragShadowBuilder code (the three lines above), and add in code to move the dragged view in the ACTION_MOVE motion event (it's commented out above):
cY1 = (int) event.getRawY();
deltaCursorY = cY1 - cY0;
v.setX(viewX0);
v.setY(viewY0 + deltaCursorY);
Then I can control the textView to move only along the Y-axis. Unfortunately, without a DragShadowBuilder, I can't get the ACTION_DRAG_ENTERED DragEvent to trigger to turn the dropZone view blue.
If I leave both the DragShadowBuilder code and the four lines of code above, the ACTION_MOVE motion event is only triggered once for a drag; it doesn't continue to follow the drag around.
Anybody have any ideas as to what I can do? I've been tooling around with this for a while, but with no luck. I even tried at one point to create a custom view that extends the Android View class, but I can't override the startDrag method because it's declared as final. I wish I were better at this. :(
Copyright Notice:Content Author:「Dog Tamer」,Reproduced under the CC 4.0 BY-SA copyright license with a link to the original source and this disclaimer.
Link to original article:https://stackoverflow.com/questions/20307246/how-do-i-restrict-drag-and-drop-along-the-y-axis-only-in-android