EDIT2: A friend of mine pointed out a much more elegant solution (Thanks!). Here it is:
@Override
public void onProvideShadowMetrics(Point shadowSize, Point shadowTouchPoint)
{
shadowSize.set((int) width + 1, (int) height + 1);
float x = offsetX - w / 2, y = offsetY - h / 2;
shadowTouchPoint.x = Math.round(x * c - y * s * sFac + w / 2 + (width - w) / 2);
shadowTouchPoint.y = Math.round(x * s * sFac + y * c + h / 2 + (height - h) / 2);
}
sFac is defined as:
float sFac = (float) Math.signum(rotationRad);
Alright, I managed to solve it with Trigonometry.
For anyone interested, here is the source code for my custom DragShadowBuilder which is used in Android to drag and drop rotated and scaled View objects:
public class TargetDragShadowBuilder extends View.DragShadowBuilder
{
ImageView view;
float offsetX, offsetY;
double rotationRad;
float w;
float h;
double s;
double c;
float width;
float height;
public TargetDragShadowBuilder(final ImageView view, float offsetX, float offsetY)
{
super(view);
this.view = view;
this.offsetX = offsetX * view.getScaleX();
this.offsetY = (int) (offsetY * view.getScaleY());
rotationRad = Math.toRadians(view.getRotation());
w = view.getWidth() * view.getScaleX();
h = (int) (view.getHeight() * view.getScaleY());
s = Math.abs(Math.sin(rotationRad));
c = Math.abs(Math.cos(rotationRad));
width = (int) (w * c + h * s);
height = (int) (w * s + h * c);
}
@Override
public void onDrawShadow(Canvas canvas)
{
canvas.scale(view.getScaleX(), view.getScaleY(), width / 2, height / 2);
canvas.rotate(view.getRotation(), width / 2, height / 2);
canvas.translate((width - view.getWidth()) / 2, (height - view.getHeight()) / 2);
super.onDrawShadow(canvas);
}
@Override
public void onProvideShadowMetrics(Point shadowSize, Point shadowTouchPoint)
{
shadowSize.set((int) width + 1, (int) height + 1);
double x = offsetX, y = offsetY;
if(rotationRad < 0)
{
final double xC = offsetX / c;
x = xC + s * (offsetY - xC * s);
final double yC = offsetY / c;
y = yC + s * (w - offsetX - yC * s);
}
else if(rotationRad > 0)
{
final double xC = offsetX / c;
x = xC + s * (h - offsetY - xC * s);
final double yC = offsetY / c;
y = yC + s * (offsetX - yC * s);
}
shadowTouchPoint.x = (int) Math.round(x);
shadowTouchPoint.y = (int) Math.round(y);
}
}
It is valid for rotations from -90° to +90°.
If anyone has a cleaner or easier solution I am still interested in it.
EDIT: And here is the code for how I handle the drop of the View object.
private class TargetDragListener implements OnDragListener
{
@Override
public boolean onDrag(View v, DragEvent e)
{
switch(e.getAction())
{
case DragEvent.ACTION_DRAG_STARTED:
break;
case DragEvent.ACTION_DRAG_ENTERED:
break;
case DragEvent.ACTION_DRAG_EXITED:
break;
case DragEvent.ACTION_DROP:
if(e.getLocalState() instanceof TargetItem)
{
TargetItem target = (TargetItem) e.getLocalState();
dropTarget(target, e.getX(), e.getY());
}
break;
case DragEvent.ACTION_DRAG_ENDED:
((DragableItem) e.getLocalState()).setVisibility(View.VISIBLE);
default:
break;
}
return true;
}
}
private void dropTarget(TargetItem target, float x, float y)
{
target.setDragged(false);
target.setVisibility(View.VISIBLE);
target.bringToFront();
final float scaleX = target.getScaleX(), scaleY = target.getScaleY();
double rotationRad = Math.toRadians(target.getRotation());
final float w = target.getWidth() * scaleX;
final float h = target.getHeight() * scaleY;
float s = (float) Math.abs(Math.sin(rotationRad));
float c = (float) Math.abs(Math.cos(rotationRad));
float sFac = (float) -Math.signum(rotationRad);
target.offsetX *= scaleX;
target.offsetY *= scaleY;
x += -target.offsetX * c - target.offsetY * s * sFac;
y += target.offsetX * s * sFac - target.offsetY * c;
float[] pts = { x, y };
float centerX = x + c * w / 2f + sFac * s * h / 2f;
float centerY = y - sFac * s * w / 2f + c * h / 2f;
transform.setRotate(-target.getRotation(), centerX, centerY);
transform.mapPoints(pts);
target.setX(pts[0] + (w - target.getWidth()) / 2);
target.setY(pts[1] + (h - target.getHeight()) / 2);
}