Search code examples
androidxamarinrotationdropshadow

Rotated Dragshadow (Xamarin, Android)


I have an rotated textview and I want to drag and drop this view. The problem is that the drag shadow has no rotation.

I found a solution for android in java but this does not work for me. Maybe I translate the code wrong

How to drag a rotated DragShadow?

class CustomDragShdowBuilder : View.DragShadowBuilder
{
    private View _view;
    public CustomDragShdowBuilder(View view)
    {
        _view = view;
    }

    public override void OnDrawShadow(Canvas canvas)
    {
        double rotationRad = Math.ToRadians(_view.Rotation);
        int w = (int)(_view.Width * _view.ScaleX);
        int h = (int)(_view.Height * _view.ScaleY);
        double s = Math.Abs(Math.Sin(rotationRad));
        double c = Math.Abs(Math.Cos(rotationRad));

        int width = (int)(w * c + h * s);
        int height = (int)(w * s + h * c);

        canvas.Scale(_view.ScaleX, _view.ScaleY, width / 2, height / 2);
        canvas.Rotate(_view.Rotation, width / 2, height / 2);
        canvas.Translate((width - _view.Width) / 2, (height - _view.Height) / 2);

        base.OnDrawShadow(canvas);
    }

    public override void OnProvideShadowMetrics(Point shadowSize, Point shadowTouchPoint)
    {
        shadowTouchPoint.Set(shadowSize.X / 2, shadowSize.Y / 2);
        base.OnProvideShadowMetrics(shadowSize, shadowTouchPoint);
    }
}

Solution

  • I found a solution for android in java but this does not work for me. Maybe I translate the code wrong

    Yes, you are translating it wrong, you did change the codes of OnDrawShadow but you didn't pay attention to OnProvideShadowMetrics, which aims at changing the size of the canvas drawing area, so you need to pass the same width and height that has been calculated by codes:

    Here is the modified version of DragShdowBuilder:

    public class MyDragShadowBuilder : DragShadowBuilder
    {
        private int width, height;
    
        // Defines the constructor for myDragShadowBuilder
        public MyDragShadowBuilder(View v) : base(v)
        {
        }
    
        // Defines a callback that sends the drag shadow dimensions and touch point back to the system.
        public override void OnProvideShadowMetrics(Android.Graphics.Point outShadowSize, Android.Graphics.Point outShadowTouchPoint)
        {
            double rotationRad = Java.Lang.Math.ToRadians(View.Rotation);
            int w = (int)(View.Width * View.ScaleX);
            int h = (int)(View.Height * View.ScaleY);
            double s = Java.Lang.Math.Abs(Java.Lang.Math.Sin(rotationRad));
            double c = Java.Lang.Math.Abs(Java.Lang.Math.Cos(rotationRad));
    
    
            //calculate the size of the canvas 
            //width = view's width*cos(rad)+height*sin(rad)
            width = (int)(w * c + h * s);
            //height = view's width*sin(rad)+height*cos(rad)
            height = (int)(w * s + h * c);
    
            outShadowSize.Set(width, height);
    
            // Sets the touch point's position to be in the middle of the drag shadow
            outShadowTouchPoint.Set(outShadowSize.X / 2, outShadowSize.Y / 2);
        }
    
        // Defines a callback that draws the drag shadow in a Canvas that the system constructs
        // from the dimensions passed in onProvideShadowMetrics().
        public override void OnDrawShadow(Canvas canvas)
        {
    
            canvas.Scale(View.ScaleX, View.ScaleY, width/2 , height/2);
            //canvas.DrawColor(Android.Graphics.Color.White);
            canvas.Rotate(View.Rotation,width/2, height / 2);
            canvas.Translate((width - View.Width)/2, (height - View.Height) / 2);
            base.OnDrawShadow(canvas);
        }
    
    }
    

    And here is the complete sample:RotatedTextViewSample