Customize controls with .NET MAUI using PlatformViewFactory

In this post we will use PlatformViewFactory to customize a control without creating a new handler.

Contextualizing

When I wrote this article about customize controls with handlers, Pedro Jesus replied to my tweet suggesting to reimplement the control using PlatformViewFactory.

PlatformViewFactory

It is a static property of ViewHandler that allows to return any implementation of ViewHandler or even the native control itself.

To register it should be added in MauiProgram.cs (or anywhere before Entry handlers will be created in the app).

public static class MauiProgram
{
    public static MauiApp CreateMauiApp()
    {
        var builder = MauiApp.CreateBuilder();
        builder
            .UseMauiApp<App>()
            .ConfigureFonts(fonts =>
            {
                fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
                fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
            });

        EntryImageHandler.Register();

        return builder.Build();
    }
}

Implementation

The difference using PlatformViewFactory is instead of creating a custom handler, the function receives the default EntryHandler allowing us to customize the native control as needed.

Android implementation

    public static class EntryImageHandler
    {
        public static void Register()
        {
            EntryHandler.PlatformViewFactory = (handler) =>
            {
                var editText = new AppCompatEditText(handler.Context);

                if (handler.VirtualView is not ImageEntry)
                    return editText;

                var element = handler.VirtualView as ImageEntry;

                if (!string.IsNullOrEmpty(element.Image))
                {
                    switch (element.ImageAlignment)
                    {
                        case ImageAlignment.Left:
                            editText.SetCompoundDrawablesWithIntrinsicBounds(GetDrawable(element.Image, handler.Context, element), null, null, null);
                            break;
                        case ImageAlignment.Right:
                            editText.SetCompoundDrawablesWithIntrinsicBounds(null, null, GetDrawable(element.Image, handler.Context, element), null);
                            break;
                    }
                }

                editText.CompoundDrawablePadding = 25;
                editText.Background.SetColorFilter(Colors.White.ToAndroid(), PorterDuff.Mode.SrcAtop);

                return editText;
            };
        }
    }

iOS implementation

 public static class EntryImageHandler
    {
        public static void Register()
        {
            EntryHandler.PlatformViewFactory = (handler) =>
            {
                var textField = new MauiTextField();

                if (handler.VirtualView is not ImageEntry)
                    return textField;

                var element = handler.VirtualView as ImageEntry;

                if (!string.IsNullOrEmpty(element.Image))
                {
                    switch (element.ImageAlignment)
                    {
                        case ImageAlignment.Left:
                            textField.LeftViewMode = UITextFieldViewMode.Always;
                            textField.LeftView = GetImageView(element.Image, element.ImageHeight, element.ImageWidth);
                            break;
                        case ImageAlignment.Right:
                            textField.RightViewMode = UITextFieldViewMode.Always;
                            textField.RightView = GetImageView(element.Image, element.ImageHeight, element.ImageWidth);
                            break;
                    }
                }
                textField.BorderStyle = UITextBorderStyle.Line;
                textField.Layer.MasksToBounds = true;

                return textField;
            };
        }
    }

Wrapping Up

You can find the full code on my GitHub.

1
Subscribe to my newsletter

Read articles from Jhonatan Oliveira directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Jhonatan Oliveira
Jhonatan Oliveira

I am an enthusiastic software developer focusing on C#, .NET, Asp.NET, Azure and Angular.