The previous post Cross-Platform Apps with Xamarin Forms and Azure Mobile Services demonstrated a simple Xamarin forms app to store and manage rebates. However, there were a few issues that impeded the user experience that should be polished up. Specifically, there are some discrepancies between the different platforms, such as different font sizes as well as a missing Page title on the Windows Phone version. Today we'll look at how we can create and use page resources to create device-specific properties allowing us to update the Rebate Reminder app to create a more unified user experience.
Device-Specific Properties
Specifying a specific font size in Xamarin forms renders differently on each device, especially Windows Phone which tends to appear smaller than expected. In these screenshots below, I specified a set font of 12 for the Label. While it renders at a readable size on Android and iOS, on Windows Phone the font appears much smaller in comparison. To resolve this, we can add a page-level font resource, taking advantage of the OnPlatform property so that the font is rendered differently on each device. You can find more details on using this property in this article from the Xamarin documentation: Working with Fonts Simply add a Page.Resources entry to the XAML and define a Font property, with a different value for each platform:
<ContentPage.Resources>
<ResourceDictionary>
<OnPlatform x:Key="standardFont" x:TypeArguments="Font">
<OnPlatform.iOS>12</OnPlatform.iOS>
<OnPlatform.Android>12</OnPlatform.Android>
<OnPlatform.WinPhone>18</OnPlatform.WinPhone>
</OnPlatform>
</ResourceDictionary>
</ContentPage.Resources>
While we could define this property directly on the Label itself, making it a page-level resource makes it reusable to any control on the page. Simply bind the Font property to this resource as shown here:
<Label Text="{Binding Name}" HorizontalOptions="FillAndExpand" Font="{StaticResource standardFont}" />
<Label Text="{Binding Location}" HorizontalOptions="End" Font="{StaticResource standardFont}" />
Now each platform now device renders with its platform-specific font. The Windows Phone text size is now more readable, creating a consistent experience for the user. I was also able to apply the same technique to handle the different sizes of buttons. By default the button font size expanded beyond the container: However, specifying a set size across the board resulted in an okay look for android, but again rendered tiny fonts for Windows Phone: Using the OnPlatform resource allows the Windows Phone version to get its own size value, evening out the buttons and making a consistent layout across the board. However, we are clearly still missing the page title on windows phone. It was suggested in this Xamarin form post that you add a label and follow the same process of font resource to resolve the issue, setting a value of 0 for Android and iOS. However, in practice I was unable to get this to work as expected, as the label continued to be visible on each platform. While this looks good on Windows Phone, it resulted in double-headers on the other platforms: Instead, let’s look at an alternative approach that I found to be a bit more intuitive.
Detecting the Current Platform with Xamarin Forms
Xamarin Forms exposes a static property, Device.OS, which can be used to identify the platform on which it is running. This property can be used to identify a Windows Phone device so that controls can be shown or hidden as needed. Using this property is as simple as exposing a property on the backing ViewModel. Here is a the property definition from the BaseViewModel of the project:
public bool IsWindowsPhone { get { return Device.OS == TargetPlatform.WinPhone; } }
This property can then be bound to the IsVisible property of the label so that it only renders on Windows Phone.
<Label Text="Stores" Font="42" IsVisible="{Binding IsWindowsPhone}" />
Using this as a base, I was able to ensure that all pages had the necessary headers on all platforms. Now as we look at each device, we see that we have a much more consistent look across all three supported platforms!
Wrapping Up and Next Steps
The Page resources give us a way to not only define reusable properties, but customize the values of those properties to each platform so that we can create a consistent experience across devices. Using this I was able to update the Rebate Reminder app with a much more consistent look. Take a look at the updated source code below to learn more:
Get the CODE!
However, one limitation to this approach is that it requires that you duplicate these resources to each page. This makes it problematic if you want to change these values, as they'll have to be updated to each page that uses them. In our next post we'll look at how we can create global resources so that all of your app properties can be maintained from a single location. Until then as always, I hope this was helpful!
Enjoyed this post and/or found it useful?