When I was building Moments, a Snapchat clone built with Xamarin.Forms and Microsoft Azure, I needed a way to show a live, in-app camera feed so users could take all the selfies their hearts desire without having to leave the app to take a photo. This type of camera access is possible in traditional Xamarin.iOS and Xamarin.Android development, which I learned how to do from our Xamarin recipes, but I knew that this type of camera access wasn’t part of Xamarin.Forms’ out-of-the-box 40+ controls, layouts, and pages.

Luckily, not only can you extend existing controls and build your own controls in Xamarin.Forms, you can also render platform-specific pages from within your Xamarin.Forms apps. This was the type of customization that I needed, and it was surprisingly simple to implement.

Moments, a Snapchat clone built with Xamarin.Forms and Azure.

Implementing a PageRenderer

User interfaces built with Xamarin.Forms look and feel native because they are native — they’re rendered using the native controls for each platform. Developers can easily tap into these native renderings of Xamarin.Forms controls by using custom renderers. There are two main types of custom renderers: renderers for controls, such as EntryRenderer, that all inherit from ViewRenderer, and a renderer for pages called PageRenderer.

As an example, you could have an app where 90% of the screens can be built using the provided Xamarin.Forms controls, but the other 10% of screens cannot. PageRenderers are perfect for those screens that require platform-specific APIs, such as the in-app camera feed in Moments. If you find yourself writing more PageRenderers than not, you should probably use the traditional Xamarin approach instead of Xamarin.Forms.

Subclassing Your Page

In the Shared Project or PCL where your Xamarin.Forms user interface logic resides, create a subclass of ContentPage:

public class CameraPage : ContentPage
{
}

Platform-Specific Implementation

Both the appearance and behavior of our page written using custom renderers will come from a platform-specific implementation. This implementation can take full advantage of 100% of the native APIs on that platform, helping you build complex pages from within a Xamarin.Forms app. To get started, create a new class for your custom page and subclass PageRenderer:

public class CameraPage : PageRenderer
{
}

iOS

Implementing custom pages from iOS is easy — PageRenderer is just a UIViewController, thus allowing you to take advantage of all of the view controller lifecycle methods, such as ViewDidLoad. This is extremely convenient as you may already have code for an existing UIViewController you want to pull into a Xamarin.Forms page, as seen below:

[assembly:ExportRenderer(typeof(Moments.CameraPage), typeof(Moments.iOS.CameraPage))]
public class CameraPage : PageRenderer
{
    public override void ViewDidLoad ()
    {
        base.ViewDidLoad ();

        SetupUserInterface ();
        SetupEventHandlers ();
        SetupLiveCameraStream ();
        AuthorizeCameraUse ();
    }

    public override void ViewDidAppear (bool animated)
    {
        base.ViewDidAppear (animated);

        SetupLiveCameraStream ();
    }
}

Android

On Android a PageRenderer is just a ViewGroup, which is, as its name implies, a grouping of views. You can add views directly to the ViewGroup, or, if you wish to work directly with the activity, access that via the Context property:

[assembly:ExportRenderer(typeof(Moments.CameraPage), typeof(Moments.Android.CameraPage))]
public class CameraPage : PageRenderer
{
    public CameraPage ()
    {
        activity = this.Context as Activity;
        view = activity.LayoutInflater.Inflate(Resource.Layout.CameraLayout, this, false);
        ...
    }
}

For both iOS and Android, if you wish to alter or subscribe to any properties of your Xamarin.Forms page from within your custom renderer, you can access it by overriding the OnElementChanged method.

Finally, to enable Xamarin.Forms to properly find and render your custom page, you must add the [assembly] attribute above the class. The first parameter references the Xamarin.Forms page in your PCL or Shared Project, while the second parameter references the platform-specific page you wish to replace it with:

[assembly:ExportRenderer(typeof(Moments.CameraPage), typeof(Moments.iOS.CameraPage))]

The Result: An In-App Camera Feed

CameraPages

Wrapping It All Up

Adding one or two platform-specific screens to your Xamarin.Forms apps is easy thanks to custom renderers! With Xamarin.Forms, you can share large amounts of code (87% in the case of Moments) and still maintain 100% access to the underlying native APIs, such as use of a live feed from the camera. To get started, check out the docs on custom renderers or view the code from Moments to start adding platform-specific screens into your Xamarin.Forms apps today.