I am using Android Drag&Drop API and am trying to set the anchor of the drag shadow to the point where the touch was made in the View
. The dafault behavior is to have the anchor the middle of the View
.
I did some research and it seems this can be done by overriding the onProvideShadowMetrics (Point shadowSize, Point shadowTouchPoint)
method in the DragShadowBuilder
class. From what I understood, if I change the x,y coordinates of shadowTouchPoint
it should modify the coordinates of the drag anchor.
What I did was to extend the DragShadowBuilder
class like so:
class EventDragShadowBuilder extends DragShadowBuilder {
int touchPointXCoord, touchPointYCoord;
public EventDragShadowBuilder() {
super();
}
public EventDragShadowBuilder(View view, int touchPointXCoord,
int touchPointYCoord) {
super(view);
this.touchPointXCoord = touchPointXCoord;
this.touchPointYCoord = touchPointYCoord;
}
@Override
public void onProvideShadowMetrics(Point shadowSize,
Point shadowTouchPoint) {
shadowTouchPoint.set(touchPointXCoord, touchPointYCoord);
super.onProvideShadowMetrics(shadowSize, shadowTouchPoint);
}
}
In the Fragment
where I use drag&drop I created two listeners to start a drag event for a View
:
mEventLongClickListener = new OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
EventDragShadowBuilder shadowBuilder = new EventDragShadowBuilder(
view, mEventTouchXCoord, mEventTouchYCoord);
view.startDrag(null, shadowBuilder, view, 0);
return true;
}
};
// We need this listener in order to get the corect coordinates for the
// drag shadow
mEventTouchListener = new OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent event) {
final int action = event.getAction();
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN: {
mEventTouchXCoord = (int) event.getX();
mEventTouchYCoord = (int) event.getY();
break;
}
}
return false;
}
};
And I set the tow listeners:
itemView.setOnLongClickListener(mEventLongClickListener);
itemView.setOnTouchListener(mEventTouchListener);
Everything ok up to here. But when I test the app and start the drag process, the drag shadow is centered under the touch point. So it uses the default behavior. I tried debugging and I see that mEventTouchXCoord
and mEventTouchYCoord
are set correctly. The method shadowTouchPoint.set(touchPointXCoord, touchPointYCoord);
gets the correct coordinates but still it centers the shadow.
I don't know what I'm doing wrong. Maybe I misunderstood the API. Any help with or hint would be much appreciated.
Ok, so like Scoup said the problem was in the onProvideShadowMetrics()
method. The fact is, if I remove the super constructor, super.onProvideShadowMetrics(shadowSize, shadowTouchPoint);
, it will not show the drag shadow anymore.
Taking a closer look at the API method this is what I found:
public void onProvideShadowMetrics(Point shadowSize, Point shadowTouchPoint) {
final View view = mView.get();
if (view != null) {
shadowSize.set(view.getWidth(), view.getHeight());
shadowTouchPoint.set(shadowSize.x / 2, shadowSize.y / 2);
} else {
Log.e(View.VIEW_LOG_TAG, "Asked for drag thumb metrics but no view");
}
}
So indeed, it resets the shadowTouchPoint
to the middle of the dragged View
. But it also initializes the drag shadow to the correct dimensions. While I want the drag shadow dimensions to be set correctly I don't want to reset shadowTouchPoint
.
The easiest way to acheive this is to call the super constructor before initializing the shadowTouchPoint
with the custom values, like so:
@Override
public void onProvideShadowMetrics(Point shadowSize,
Point shadowTouchPoint) {
super.onProvideShadowMetrics(shadowSize, shadowTouchPoint);
shadowTouchPoint.set(touchPointXCoord, touchPointYCoord);
}
Another solution is to deal with the drag shadow View
yourself and skip the super constructor altogether. I will get back with a detailed update.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With