Platform Specifics in Xamarin Forms

Platform specifics allow you to enhance a control in Xamarin Forms on a particular platform. Now you can add specific platform only properties to Xamarin Forms controls, starting with Xamarin Forms 2.3.3, in Shared and PCL based projects in either code behind or XAML.

Built-in Platform Specifics

Xamarin Forms comes with built-in platform specifics. You have two options of either using the Fluent API in code behind or in XAML. Some of the existing built-in platform-specifics are:

  1. [iOS] BlurEffect [Any VisualElement]
  2. [iOS] NavigationBarTranslucent [NavigationBar]
  3. [Windows] ToolbarPlacement [Page]
  4. [Windows] CollapseStyle [MasterDetailPage]
  5. [Android] WindowsSoftInputModeAdjust [Application]

For an example, I have gone withe BlurEffect below.

XAML

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:iOSSpecific="clr-namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
             x:Class="ExrinSample.View.LoginView">
    <Grid Padding="20">
        <StackLayout>
            <Entry Text="HelloWorld" iOSSpecific:VisualElement.BlurEffect="Dark" />
        </StackLayout>
    </Grid>
</ContentPage>

Fluent API

myVisualElement.On<Xamarin.Forms.PlatformConfiguration.iOS>().UseBlurEffect(BlurEffectStyle.Dark);

Here you can compare running in iOS and running in UWP


blurios bluruwp
 

As you can see, it does nothing in UWP, but implements a dark blur over the Entry control in iOS.

Creating a Platform Specific

In this example I will walk through how they implemented the blur effect in the Xamarin Forms source code. You can do similar with any other control and custom renderer. First we create a static class of the same name you want to override in the iOSSpecific namespace.

You add in your bindable property and your method extensions, to support the Fluent API approach.

namespace Xamarin.Forms.PlatformConfiguration.iOSSpecific
{
    using FormsElement = Forms.VisualElement;

    public static class VisualElement
    {
        public static readonly BindableProperty BlurEffectProperty =
        BindableProperty.Create("BlurEffect", typeof(BlurEffectStyle),
        typeof(VisualElement), BlurEffectStyle.None);

        public static BlurEffectStyle GetBlurEffect(BindableObject element)
        {
            return (BlurEffectStyle)element.GetValue(BlurEffectProperty);
        }

        public static void SetBlurEffect(BindableObject element, BlurEffectStyle value)
        {
            element.SetValue(BlurEffectProperty, value);
        }

        public static BlurEffectStyle GetBlurEffect(this IPlatformElementConfiguration<iOS, FormsElement> config)
        {
             return GetBlurEffect(config.Element);
        }
 
        public static IPlatformElementConfiguration<iOS, FormsElement> UseBlurEffect(this IPlatformElementConfiguration<iOS, FormsElement> config, BlurEffectStyle value)
        {
             SetBlurEffect(config.Element, value);
             return config;
        }
    }
}

Next you need to modify the renderer for VisualElements.

Next in your OnElementPropertyChanged, you will can detect the BlurEffect property changing and implement the blur.

protected virtual void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
    if (e.PropertyName == PlatformConfiguration.iOSSpecific.VisualElement.BlurEffectProperty.PropertyName)
        SetBlur((BlurEffectStyle)Element.GetValue(PlatformConfiguration.iOSSpecific.VisualElement.BlurEffectProperty));
}

protected virtual void SetBlur(BlurEffectStyle blur)
{
    if (_previousBlur == blur)
    return;

    _previousBlur = blur;

    if (_blur != null)
    {
        _blur.RemoveFromSuperview();
        _blur = null;
    }

    if (blur == BlurEffectStyle.None)
    {
        SetNeedsDisplay();
        return;
    }

    UIBlurEffect blurEffect;
    switch (blur)
    {
        default:
        case BlurEffectStyle.ExtraLight:
            blurEffect = UIBlurEffect.FromStyle(UIBlurEffectStyle.ExtraLight);
            break;
        case BlurEffectStyle.Light:
            blurEffect = UIBlurEffect.FromStyle(UIBlurEffectStyle.Light);
            break;
        case BlurEffectStyle.Dark:
            blurEffect = UIBlurEffect.FromStyle(UIBlurEffectStyle.Dark);
            break;
     }

     _blur = new UIVisualEffectView(blurEffect);
     SetNeedsDisplay();
}

If the renderer doesn’t support the property changed, as it won’t in other platforms, the other platforms will do nothing with the property.

Thoughts

I currently have my reservations about this feature. The fact you have to create your own by either creating a Custom Renderer, using Effects or some other means, it seems like it is more work, for no gain. If you keep watching the list of Platform Specifics and know when to use one, it can save some time. Its one to keep an eye on, however this feature might be one that soon gets neglected due to lack of use and hassle to add a new platform specific feature on a control. Surfacing these properties to the Xamarin developer isn’t intuitive and will most likely remain hidden from them.

I believe the only purpose of this feature is to allow Xamarin and 3rd Party component developers to create a separate namespace for their controls, to implement native functionality. Rather than the other option of confusing developers, by having a property on a Xamarin Forms control that only works on a single or limited number of platforms but appears to be available for all.

Microsoft MVP (Xamarin) | Exrin | Xamarin Forms Developer | Melbourne, Australia | Open to sponsorship to Canada or US

Related Posts

2 Comments

  1. Rodrigo Díaz Concha

    This feature opens the door to spaghetti code IMHO. I do prefer the Custom Renderers way of architecting the applications with XF.

    1. Adam Pedley

      I agree with you there. It really seems like its only meant to be enhanced by Xamarin and developers are just meant to use whats in the framework. Otherwise as you said, its much easier just implementing your own custom renderer.

Leave A Comment?