Set custom snap when dragging a view

I use the Android Drag & Drop API and try to set the shadow tag to the point at which the touch was made in the View . The dafault behavior should contain an anchor in the middle of the View .

I did some research, and it seems like you can do this by overriding the onProvideShadowMetrics (Point shadowSize, Point shadowTouchPoint) in the DragShadowBuilder class. From what I understood, if I changed the x, y shadowTouchPoint , it should change the binding snap coordinates.

What I did was extend the DragShadowBuilder class as follows:

 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 Fragment , where I use drag & drop, I created two listeners to fire a drag event for the 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 installed the towers:

 itemView.setOnLongClickListener(mEventLongClickListener); itemView.setOnTouchListener(mEventTouchListener); 

Everything is fine. But when I test the application and start the drag and drop process, the drop shadow is centered under the touch point. Therefore, it uses the default behavior. I tried debugging and I see that mEventTouchXCoord and mEventTouchYCoord set correctly. shadowTouchPoint.set(touchPointXCoord, touchPointYCoord); method shadowTouchPoint.set(touchPointXCoord, touchPointYCoord); gets the correct coordinates, but nonetheless it centers the shadow.

I do not know what I am doing wrong. Perhaps I misunderstood the API. Any help with a hint would be greatly appreciated.

+7
android drag-and-drop
source share
2 answers

Good, since Scoup said the problem was in the onProvideShadowMetrics() method. The fact is that if I remove the super constructor, super.onProvideShadowMetrics(shadowSize, shadowTouchPoint); , it will no longer display the drop shadow.

We’ll take a closer look at the API method 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"); } } 

Thus, it resets the shadowTouchPoint to the middle of the dragged View . But it also initializes the drop shadow for the correct size. Although I want the shadow shadow dimensions to be set correctly, I don't want to reset shadowTouchPoint .

The easiest way to achieve this is to call the super constructor before , initializing the shadowTouchPoint using custom values, for example:

 @Override public void onProvideShadowMetrics(Point shadowSize, Point shadowTouchPoint) { super.onProvideShadowMetrics(shadowSize, shadowTouchPoint); shadowTouchPoint.set(touchPointXCoord, touchPointYCoord); } 

Another solution is to deal with the View shadow tag yourself and generally skip the super constructor. I will be back with a detailed update.

+11
source share

I think the problem is in this line super.onProvideShadowMetrics(shadowSize, shadowTouchPoint);

You have already changed the value of shadowTouchPoint to shadowTouchPoint.set(touchPointXCoord, touchPointYCoord); but when you call super, you pass shadowTouchPoint, which is replaced by the default super method, and the default behavior is the center of shadowTouchPoint.

So just delete this line.

+7
source share

All Articles