Adding simple drag and drop to a game using Xamarin Forms and SkiaSharp

In the previous part we detected touch presses. In this part we are adding more SkiaSharp touch events and implement simple drag and drop. See the official documentation for more advanced touch interaction with gestures at Xamarin Touch events and Touch tracking

The MainPage.xaml.cs from the previous part is extended with the SKTouchAction.Moved and SKTouchAction.Released event in the OnTouching method, which sends the touch information to the pixel app.

    public partial class MainPage : ContentPage
    {
        // See previous articles for the remaining code

        // Handle the touch events and send it to the PixelApp. Note, to enable other events, set e.Handled = true;
        private void OnTouching(object sender, SKTouchEventArgs e)
        {
            switch (e.ActionType)
            {
                case SKTouchAction.Pressed:
                    _pixelApp.OnPressed(e.Location);
                    break;
                case SKTouchAction.Moved:
                    _pixelApp.OnMoved(e.Location);
                    break;
                case SKTouchAction.Released:
                    _pixelApp.OnReleased(e.Location);
                    break;
            }          

            // Handle event to indicate we are interested in other events
            e.Handled = true;
        }
    }		
	

The PixelApplication class gets new methods OnPressed, OnMoved and OnReleased which have the touch location as a SKPoint argument. The pressed point and the released point are stored in a list, which is rendered in the Render method using the canvas DrawRect method to visualize the start of the drag and the drop of the rectangle through the release event. The dragging itself is rendered from the movePoint.

    public class PixelApplication
    {
        // See the refactor blog for the remaining code, it is the same as there.
		
        private List touches = new List();
        SKPoint movePoint;
        SKPoint pressedPoint;
        bool isDragging;
        bool isPressed;
		
        public void OnPressed(SKPoint point)
        {
            // Store the press location for rendering
            touches.Add(point);

            // Store the location of the pressed event
            pressedPoint = point;
			
            // Store the pressed state
            isPressed = true;
        }

        public void OnMoved(SKPoint point)
        {
            movePoint = point;

            if (isPressed)
            {
                // Calculate the distance between the start of the press and the moved point 
                var delta = movePoint - pressedPoint;

                // If the distance is larger than a threshold indicate that dragging has started
                if (delta.LengthSquared > 16.0f)
                    isDragging = true;
            }
        }

        public void OnReleased(SKPoint point)
        {
		    // Store the drop location
            touches.Add(point);

            // Store that dragging and pressing has ended
            isPressed = false;
            isDragging = false;
        }

        public void Render(SKCanvas canvas, double updateDelta)
        {
            // Extra elapsed time since last stopwatch restart
            var dt = updateDelta + remainingTime;

            // Update the position with the extra elapsed time distance
            float xp = (float)(x + dt * vx);
            float yp = (float)(y + dt * vy);

            canvas.Clear(_fillColor);

            using (SKPaint skPaint = new SKPaint())
            {
                skPaint.Style = SKPaintStyle.Fill;
                skPaint.IsAntialias = true;
                skPaint.Color = SKColors.Blue;
                skPaint.StrokeWidth = 10;

                // Draw a rectangle whose center is the touch point
                foreach (var p in touches)
                    canvas.DrawRect(p.X-50.0f, p.Y-50.0f, 100.0f, 100.0f, skPaint);

                // If is dragging, draw a rectangle at the current move location, this visualizes the drag
                if (isDragging)
                    canvas.DrawRect(movePoint.X - 50.0f, movePoint.Y - 50.0f, 100.0f, 100.0f, skPaint);

                canvas.DrawCircle(xp, yp, r, skPaint);
            }
        }
    }
	

After this tutorial you can click the canvas and a rectangle should appear. The dragging of this rectangle by moving the pointer in a pressed state is visualized. Finally, when the dragging ends by releasing the touch, a rectangle is rendered at the release point, thereby performing the drop of the rectangle to that location.