Creating a drawing app using Xamarin.Forms

So Xamarin released an update (v3) last week and it is truly a huge step forward for mobile developers.  So if you are interested in cross-platform development and haven’t reviewed what Xamarin has done, then you need to stop what you’re doing and go look.

Xamarin is having a contest to showcase their new Xamarin.Forms functionality added to Xamarin 3.  I spent the good part of last weekend reviewing everything that I could find regarding Xamarin.Forms and was in my chair coding by 7:00am Monday morning.

This is the story of what I created.

 

Introducing DrawIt

Imagine a cross-platform drawing tool.  Yeah, I know, they probably exist but I didn’t let that get in my way.  This is a very simple drawing application that allows you to draw with your finger, using a pen color of your choice.

Here is the iOS/iPad version:

XamarinRocks

The Android version:

image

The Windows Phone version:

SNAGHTML35b07ae

Unfortunately, I was not able to get actual drawing mechanism working on WinPhone, so all we have at this point is the UI.

 

How it Works

I create a Xamarin.Forms shared-code project which created the following Visual Studio solution:

image

DrawIt is the shared-code project while the others exist to provide a platform-specific layer that the shared-code will reside upon.

Within the shared-code project, I started off with a custom class that inherited from Image that would allow me to specify a line color.

 

ImageWithTouch Class

public class ImageWithTouch : Image 
    {
        public static readonly BindableProperty CurrentLineColorProperty = 
            BindableProperty.Create ((ImageWithTouch w) => w.CurrentLineColor, Color.Default);

        public Color CurrentLineColor {
            get {
                return (Color)GetValue (CurrentLineColorProperty);
            }
            set {
                SetValue (CurrentLineColorProperty, value);
            }
        }
    }

 

Creating the User Interface

The best part of Xamarin.Forms is that I have a single codebase for the user interface, that looks something like this:

public MainPage()
{
    Content = BuildGrid();

    // Accomodate iPhone status bar.
    Padding = new Thickness(10, Device.OnPlatform(20, 0, 0), 10, 10);
}

private Grid BuildGrid()
{
    return new Grid
    {
        VerticalOptions = LayoutOptions.FillAndExpand,
        HorizontalOptions = LayoutOptions.FillAndExpand,
        RowDefinitions = {
            new RowDefinition {
                Height = GridLength.Auto
            },
            new RowDefinition {
                Height = new GridLength (1, GridUnitType.Star)
            },
        },
        ColumnDefinitions = {
            new ColumnDefinition {
                Width = new GridLength (100, GridUnitType.Absolute)
            },
            new ColumnDefinition {
                Width = new GridLength (1, GridUnitType.Star)
            },
        },
        Children =
        {
            {new Label {
                Text = "Draw It",
                Font = Font.BoldSystemFontOfSize (50),
                HorizontalOptions = LayoutOptions.CenterAndExpand,
                VerticalOptions = LayoutOptions.FillAndExpand
                }, 0, 2, 0, 1},
            {BuildPalletFrame(), 0, 1},
            {new ContentView {
                Content = BuildDrawingFrame(),
                Padding = new Thickness(10, 0, 0, 0),
                HorizontalOptions = LayoutOptions.FillAndExpand,
                VerticalOptions = LayoutOptions.FillAndExpand
            }, 1, 1}
        }
    };
}

The UI elements exist within a fixed-size grid that is fitted to the screen for whatever device the application is running on.

All of the code you have seen so far is cross-device compatible and exists within a Shared project used by the device-specific projects

 

Custom Renderers

In order to provide the low-level drawing capabilities, I had to create what is called a custom-renderer for each of the device platforms. This is what actually creates the drawing surface for each device.  Here is the renderer for iOS:

[assembly: ExportRenderer(typeof(ImageWithTouch), typeof(ImageWithTouchRenderer))]
namespace DrawIt.iOS
{
    public class ImageWithTouchRenderer : ImageRenderer
    {
        protected override void OnModelSet(VisualElement model)
        {
            base.OnModelSet(model);

            SetNativeControl(new DrawView(Control.Frame));
        }

        protected override void OnHandlePropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            base.OnHandlePropertyChanged(sender, e);

            if (e.PropertyName == ImageWithTouch.CurrentLineColorProperty.PropertyName)
            {
                ((DrawView)Control).CurrentLineColor = ((ImageWithTouch)Model).CurrentLineColor.ToUIColor();
            }
        }
    }
}

The other two projects have similar renderers. The code that actually does the work is in a class called DrawView, which merely creates an ImageView that can be drawn upon using the native drawing mechanisms for the device.

 

Wrapping It Up

This was a fun little project and I barely touched the surface of what Xamarin.Forms can do.  I am still rather shocked at the small amount of code that I had to write to get a standard user interface across all three platforms.

Drop me a line and let me know what you think.

 

Source

You can view my source on GitHub here:

https://github.com/MitchMilam/Drawit/tree/master

Leave a Reply 13 comments