Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to drag a rotated DragShadow?

I rotated a TextView with ObjectAnimator like this:

ObjectAnimator rotate = ObjectAnimator.ofFloat(aRotatedTextView, "rotation", 0f, someAngle);

Now, I try to drag and drop the rotated(!) TextView on long click like this:

public boolean onLongClick(View view) {
    ClipData data = ClipData.newPlainText("DragData", (String) view.getTag());
    DragShadowBuilder dragShadowBuilder = new View.DragShadowBuilder(view);
    mDragInProgress = view.startDrag(data, dragShadowBuilder, view, 0);
    view.setVisibility(View.INVISIBLE);
    return true;
}

What happens is that a DragShadow is created without rotation (angle==0). I've seen quite a few examples with bitmaps (but not with rotation) that I wasnt able to get working. Is there a way to create a rotated DragShadow?

like image 556
user2475481 Avatar asked Feb 17 '23 06:02

user2475481


2 Answers

Needed the same thing. Implemented it like this (scaling also included)

new OnTouchListener() {
    @Override
    public boolean onTouch(final View view, MotionEvent event) {

    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
    double rotationRad = Math.toRadians(view.getRotation());
    final int w = (int) (view.getWidth() * view.getScaleX());
    final int h = (int) (view.getHeight() * view.getScaleY());
    double s = Math.abs(Math.sin(rotationRad));
    double c = Math.abs(Math.cos(rotationRad));
    final int width = (int) (w * c + h * s);
    final int height = (int) (w * s + h * c);
    DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(view) {
        @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(width, height);
            shadowTouchPoint.set(shadowSize.x / 2, shadowSize.y / 2);
        }
    };

    view.startDrag(null, shadowBuilder, view, 0);
    ...
}
like image 72
vir us Avatar answered Feb 27 '23 19:02

vir us


I have been going around in circles with this myself and haven't found much help on various forums.

My observation is that even when the view is rotated, the canvas that is provided to the shadow builder is in original un-rotated state.

The closest I got to a properly rotated drag shadow was by implementing a custom shadow builder and passing it the current rotation of the view being dragged.

In onProvideShadowMetrics(Point size, Point touch), I set the shadow dimensions based on the current rotation so that for rotated views, there would be enough height for the shadow to be drawn

In onDrawShadow(Canvas canvas), I take into account the rotation again and roate the canvas by the same amount as the view. I then let the base class create the actual shadow by calling super.onDrawShadow(canvas). The point of rotation is the same as that used when rotating the actual view.

The end result is that I have a rotated drag shadow which is partially clipped. It appears that even though the canvas rotation is being used in the base class, the drawing point is so close to the edge of the canvas that part of the shadow gets clipped. I have not been able to work out how to adjust the canvas so that the drawing in the base class gets done at the right offset to prevent the clipping.

It appears that I will probably end up doing all the shadow drawing myself without relying on the base class.

good luck.

m.a

Update:

Thank you Vi rus. I've finally revisited this part of my app and tried your suggested approach which has worked quite well. I can't vote up since I don't have enough points etc.

like image 21
m.a Avatar answered Feb 27 '23 18:02

m.a