.NET MAUI – Exploring Overlays – Part 2

This is post #4 in a series called ‘.NET MAUI Source of Truth’.

About Source Of Truth – As any developer knows, source code is the purest form of truth in working software. So I’ve decided the best way to get deep into .NET MAUI is to look at the source code.

In my last posts, we explored the .NET MAUI codebase learning about the new Windows functionality, and then managed to get a demo of them working in Preview11. Then we’ve dived into overlays in .NET MAUI.

After writing my previous post on Overlays I found an interesting piece of code in the .NET MAUI codebase. This code was basically a advanced implementation of a WindowsOverlay. This was called the VisualDiagnosticsOverlay and I also managed to find a good sample project called DrasticOverlay created by https://twitter.com/drasticactionSA.

This sample project is a good example of what can be done with overlays. This sample project has example of Overlays, Background Overlays, Hit Detection Overlays, Videos, Menus, Loading, Drag and Drop and more.

Looking through this codebase we can see the different overlays that have been created, see below.

In this case, let’s dig into the drag and drop overlay to see how these awesome overlays are working. The basic implementation of an overlay is a partial class that inherits from WindowOverlay. The partial class combined with multi-targeting allows for common code and native implementations to nicely sit side by side.

Below, I’ve included the DragAndDropOverlay code. In this, we can see our partial class and inheritance from WindowOverlay. Overall it’s a fairly simple class that has a drop element, which is a IWindowOverlayElement. In this case the element is using the drawing capabilities available in .NET MAUI. Then a simple event handler and IsDragging property.

public partial class DragAndDropOverlay : WindowOverlay
{
    DropElementOverlay dropElement;
    bool dragAndDropOverlayNativeElementsInitialized;

    internal bool IsDragging
    {
        get => dropElement.IsDragging;
        set
        {
            dropElement.IsDragging = value;
            this.Invalidate();
        }
    }

    public DragAndDropOverlay(IWindow window)
        : base(window)
    {
        this.dropElement = new DropElementOverlay();
        this.AddWindowElement(dropElement);
    }

    public event EventHandler<DragAndDropOverlayTappedEventArgs>? Drop;

    class DropElementOverlay : IWindowOverlayElement
    {
        public bool IsDragging { get; set; }
        // We are not going to use Contains for this.
        // We're gonna set if it's invoked externally.
        public bool Contains(Point point) => false;

        public void Draw(ICanvas canvas, RectangleF dirtyRect)
        {
            if (!this.IsDragging)
                return;

            // We're going to fill the screen with a transparent
            // color to show the drag and drop is happening.
            canvas.FillColor = Color.FromRgba(225, 0, 0, 100);
            canvas.FillRectangle(dirtyRect);
        }
    }
}

As we can see in the previous image there are native implementations on Windows, iOS and Android. Let’s now take a look at the iOS partial class, this class is named DragAndDropOverlay.iOS.cs. You can see the full file over here:

Below is the Initialize() method on the iOS implementation. There’s a native view called DragAndDropView and this is added as a subview on the nativeWindow?.

// We're going to create a new view.
// This will handle the "drop" events, and nothing else.
dragAndDropView = new DragAndDropView(this, nativeWindow.RootViewController.View.Frame);
dragAndDropView.UserInteractionEnabled = true;
nativeWindow?.RootViewController.View.AddSubview(dragAndDropView);
nativeWindow?.RootViewController.View.BringSubviewToFront(dragAndDropView);

Below we can see part of the DragAndDropView which is implemented in the iOS code. We can see that it’s making use of native APIs eg UIView and IUIDropInteractionDelegate.

class DragAndDropView : UIView, IUIDropInteractionDelegate
{
    DragAndDropOverlay overlay;

    public DragAndDropView(DragAndDropOverlay overlay, CGRect frame)
        : base(frame)
    {
        this.overlay = overlay;
        this.AddInteraction(new UIDropInteraction(this));
    }

    [Export("dropInteraction:canHandleSession:")]
    public bool CanHandleSession(UIDropInteraction interaction, IUIDropSession session)
    {
        Console.WriteLine($"CanHandleSession ({interaction}, {session})");

        return session.CanLoadObjects(new Class(typeof(UIImage)));
    }
    ...
}

In looking at the majority of the implementations they all follow a similar pattern to the DragAndDrop Overlay. As mentioned previously you can implement Overlay on multiple levels, so you can use the Cross-Platform drawing methods available in .NET MAUI and you can also do native implementations for each platform.

If you are interested in overlays I would recommend taking a look at this cool sample project – DrasticOverlay and the VisualDiagnosticOverlay from the .NET MAUI codebase.

Overall it’s nice to see that we can implement this level of functionality within overlays in .NET MAUI. Ideally I would like to see support for .NET MAUI controls inside overlays, presently I’m not sure how we could implement this but I suspect it would be possible.

Leave a Reply