I'm trying to get X, Y coordinates while I'm dragging my button, but for some reason, the code bellow attached on touch listener triggers only twice instead of constant update while dragging, even with trothing I will be satisfied in order to improve performance, but as I said, onTouch
method triggered just on action down, and one more time later.
This is my code:
final Button dragBtn = (Button) findViewById(R.id.MyTestButton);
dragBtn.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent me) {
// TODO Auto-generated method stub
ClipData data = ClipData.newPlainText("", "");
View.DragShadowBuilder shadow = new View.DragShadowBuilder(dragBtn);
v.startDrag(data, shadow, null, 0);
int action = me.getAction();
if (action==MotionEvent.ACTION_DOWN) {
Log.i("TEST", "ACTION_DOWN");
return true;
}
if (action==MotionEvent.ACTION_MOVE){
Log.i("TEST", "ACTION_MOVE");
float x = me.getX();
float y = me.getY();
//TODO: Rest of my code here.
return true;
}
if (action==MotionEvent.ACTION_UP){
Log.i("TEST", "ACTION_UP");
return true;
}
Log.i("TEST", "UKNOWN ACTION");
return true;
}
});
And in log I have just:
ACTION_DOWN
WindowManager﹕ Drag already in progress
UKNOWN ACTION
You want to capture the X and Y coordinate data in your OnDragListener
not your OnTouchListener
. For the whole time that you are dragging the object around the screen, Android interprets that as one single ACTION_MOVE event, hence you only get data once from that. Place the following code inside your custom OnDragListener
class:
@Override
public boolean onDrag(View v, DragEvent event) {
int action = event.getAction();
float xCoord;
float yCoord;
if(action == DragEvent.ACTION_DRAG_LOCATION) {
xCoord = event.getX();
yCoord = event.getY();
}
return event.getResult(); //returns true for valid drop or false for invalid drop
}
Somewhere else in your custom OnDragListener
class, you will have to do something with that xCoord and yCoord data. For example in my app, I have a TextView
on my "debug" version of the app where I display the xCoord and yCoord data. I execute the TextView.setText()
method right after I get those two values in my if(action == DragEvent.ACTION_DRAG_LOCATION){...
section.
Hope this helps.
MotionEvent.getAction encodes the action type as well as additional pointer information (for multi-touch handling). You want MotionEvent.getActionMasked to get just the action part.
Edit: also, per discussion below there's some issue with startDragging.
Once the system has the drag shadow, it begins the drag and drop operation by sending drag events to all the View objects in your application that are currently visible. It does this either by calling the View object's drag listener (an implementation of onDrag() or by calling the View object's onDragEvent() method. Both are passed a DragEvent object that has a getAction() value of ACTION_DRAG_STARTED
finaly your code should be like this.
int basex;
int basey;
RelativeLayout.LayoutParams layoutParams;
RelativeLayout layBg;
....................
dragBtn.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent me) {
// TODO Auto-generated method stub
layoutParams = (RelativeLayout.LayoutParams) dragBtn.getLayoutParams();
switch (me.getAction()) {
case MotionEvent.ACTION_DOWN:
basex = ((int) (me.getRawX() - layoutParams.leftMargin));
basey = ((int) (me.getRawY() - layoutParams.topMargin));
break;
case MotionEvent.ACTION_MOVE:
int i = (int) event.getRawX();
int j = (int) event.getRawY();
layBg = ((RelativeLayout) dragBtn.getParent());
if ((i - basex > -(dragBtn.getWidth() * 2 / 3))
&& (i - basex < layBg.getWidth() - dragBtn.getWidth() / 3)) {
layoutParams.leftMargin = (i - basex);
}
if ((j - basey > -(dragBtn.getHeight() * 2 / 3))
&& (j - basey < layBg.getHeight() - dragBtn.getHeight() / 3)) {
layoutParams.topMargin = (j - basey);
}
layoutParams.rightMargin = -1000;
layoutParams.bottomMargin = -1000;
dragBtn.setLayoutParams(layoutParams);
break;
}
return true;
}
});