May 22, 2017

Platform specific UI changes in Xamarin.Form


Brief: Walkthrough on the options available in xamarin form for changing UI element behaviour for specific platform.

Description: Xamarin form wrapper UI controls when it renders in each platform shows the native look and feel but still there are some quirks that has to be worked around to get the UI perfection.

For example if i add one label in my xamal page and on run in android and iOS shows the below output:
<?xml version="1.0" encoding="utf-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:CodeLog" x:Class="CodeLog.CodeLogPage">
<RelativeLayout HorizontalOptions="FillAndExpand"  >
    <Label Text="Code Log" 
          FontSize="25" 
          FontFamily="Roboto-Bold" 
          HorizontalTextAlignment="Center" 
   HorizontalOptions="FillAndExpand" />  
</RelativeLayout>
</ContentPage>
In iOS label has been overlapped with toolbar. So alone for iOS we need add To padding(Tool bar height 20px).

This kind of changes for particular platform can be achieved by using the below mentioned approaches without using the Custom renderer.

1.Using a generic class OnPlatform
2.PlatformConfiguration(https://blog.xamarin.com/bringing-platform-specific-functionality-to-xamarin-forms-apps/)
3.Bindable Native Views in Xamal page (https://blog.xamarin.com/adding-bindable-native-views-directly-to-xaml/)
4.customisation with effects(https://blog.xamarin.com/customizing-xamarin-forms-controls-with-effects/)
In this article i will be making use of the OnPlatform for different UI control properties. From Xamarin.Forms version 2.3.4, Device.OnPlatform API has been deprecated with OnPlatform and On APIs.
 <?xml version="1.0" encoding="utf-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:CodeLog" x:Class="CodeLog.CodeLogPage">
<RelativeLayout HorizontalOptions="FillAndExpand"  >
  <RelativeLayout.Margin>
    <OnPlatform x:TypeArguments="Thickness">
      <On Platform="iOS" Value="0,20,0,0" />
      <On Platform="Android, WinPhone, Windows" Value="0,0,0,0" />
    </OnPlatform>
  </RelativeLayout.Margin>
    <Label Text="Code Log" FontSize="25" FontFamily="Roboto-Bold" HorizontalTextAlignment="Center" 
  HorizontalOptions="FillAndExpand" />  
</RelativeLayout>
</ContentPage> 
Platform specific Text color:
 <Label Text="Code Log" FontSize="18" FontAttributes="Bold"  FontFamily="Roboto-Bold" XAlign="Center"  HorizontalTextAlignment="Center" 
 HorizontalOptions="FillAndExpand"
 RelativeLayout.WidthConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width, Factor=1}"> 
  <Label.TextColor>
    <OnPlatform x:TypeArguments="Color" iOS="Red" Android="Blue"  />
     </Label.TextColor> 
   </Label>  

Platform specific FontFamily:
<Label Text="Code Log" FontSize="18" FontAttributes="Bold"  FontFamily="Roboto-Bold" XAlign="Center"  HorizontalTextAlignment="Center" 
 HorizontalOptions="FillAndExpand" 
 RelativeLayout.WidthConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width, Factor=1}"> 
   <Label.FontFamily>
  <OnPlatform x:TypeArguments="x:String">
          <On Platform="iOS" Value="MarkerFelt-Thin" />
          <On Platform="Android" Value="Roboto-Regular" />
  </OnPlatform>
  </Label.FontFamily>
 </Label> 
Platform specific Button radius[for android custom renderer may required]
 <<Button Text="CodeLog"  WidthRequest="125" FontSize="16" FontAttributes="Bold" BorderColor="Teal" BorderWidth="2" BackgroundColor="White" TextColor="Black"  FontFamily="Roboto-Bold" HorizontalOptions="Center"  
 RelativeLayout.WidthConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width, Factor=1}" >
    <Button.BorderRadius>
  <OnPlatform x:TypeArguments="x:Int32"  iOS="20" Android="65"> 
  </OnPlatform>
 </Button.BorderRadius>
   </Button>
Platform specific styles:
Open App.xaml (Application.Resources) and add the styles as follows. FontSize is changed according to the platform. Here x:TypeArguments depends on the type of value that FontSize property accepts. here it is Double [https://developer.xamarin.com/api/property/Xamarin.Forms.Label.FontSize/]
?xml version="1.0" encoding="utf-8"?>
<Application xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="CodeLog.App">
 <Application.Resources>
   <ResourceDictionary>
     <Style x:Key="CustomButtonStyle" TargetType="Button">
        <Setter Property="BackgroundColor" Value="#0080BC" />
        <Setter Property="HeightRequest" Value="40" />
        <Setter Property="FontSize" Value="16" />
        <Setter Property="TextColor" Value="#FFFFFF" />
        <Setter Property="FontFamily" Value="Roboto-Regular" /> 
        <Setter Property="BorderRadius" Value="5" />
  <Setter Property="FontSize">
          <Setter.Value>
            <OnPlatform x:TypeArguments="x:Double" Android="16" iOS="14"  />
          </Setter.Value>
        </Setter>
      </Style>
 </ResourceDictionary>
  </Application.Resources>
</Application>
Open the content page and refer the style defined in the application Resources file.
<Button Text="CodeLog" Style="{StaticResource CustomButtonStyle}" BorderWidth="2" HorizontalOptions="Center"  
  RelativeLayout.WidthConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width, Factor=1}" > 
</Button>
Platform specific LayoutOptions:
 <Button Text="CodeLog" Margin="0,120,0,0"  WidthRequest="125" FontAttributes="Bold" BorderColor="Teal" BorderWidth="2" BackgroundColor="White" TextColor="Black"  FontFamily="Roboto-Bold"  
 RelativeLayout.WidthConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width, Factor=1}" > 
  <Button.VerticalOptions>
        <OnPlatform x:TypeArguments="LayoutOptions" iOS="End" Android="Center" />
      </Button.VerticalOptions>
      <Button.HorizontalOptions>
        <OnPlatform x:TypeArguments="LayoutOptions" iOS="Center" Android="Center" />
      </Button.HorizontalOptions>   
   </Button> 
Platform specific Translation:
  <Button Text="CodeLog" Margin="0,120,0,0"  WidthRequest="125" FontAttributes="Bold" BorderColor="Teal" BorderWidth="2" BackgroundColor="White" TextColor="Black"  FontFamily="Roboto-Bold"  
 RelativeLayout.WidthConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width, Factor=1}" > 
   <Button.TranslationX>
     <OnPlatform x:TypeArguments="x:Double" iOS="-10" Android="0" />
   </Button.TranslationX>
  <Button.TranslationY>
     <OnPlatform x:TypeArguments="x:Double" iOS="-10" Android="0" />
   </Button.TranslationY>  
   </Button> 
Platform specific HeightRequest and WidthRequest:
<Button Text="CodeLog" Margin="0,120,0,0"  WidthRequest="125" FontAttributes="Bold" BorderColor="Teal" BorderWidth="2" BackgroundColor="White" TextColor="Black"  FontFamily="Roboto-Bold"  
 RelativeLayout.WidthConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width, Factor=1}" > 
      <Button.HeightRequest>
     <OnPlatform x:TypeArguments="x:Double" iOS="44" Android="50" />
   </Button.HeightRequest>
   <Button.WidthRequest>
     <OnPlatform x:TypeArguments="x:Double" iOS="44" Android="50" />
   </Button.WidthRequest>
   </Button> 
Platform specific Constraint:
<RelativeLayout>
  <Label Text="Foo">
    <RelativeLayout.XConstraint>
      <OnPlatform x:TypeArguments="Constraint" Android="{ConstraintExpression Type=Constant,Constant=6}" iOS="{ConstraintExpression Type=Constant,Constant=3}" />
    </RelativeLayout.XConstraint>
  </Label>
</RelativeLayout>
Final Touch:  Most of the business requirement demands similar look and feel in android and iOS, but when few Form UI specific API's rendered in a particular platform we can observe difference in the output behaviour. For that UI fine tuning these properties are helpful.