Xamarin Guide 11: Create a LoginView

Scope

This Xamarin Workshop Guide was created for the The Portuguese National Meeting of IT Students (ENEI) by Sara Silva and the original content is available here. To extend it to the global community, it was published in a new project called Xam Community Workshop and the main goal is for any developer or user group to customize it for their events.

Before reading this article you must read:

Create a LoginView

In this step you will learn how to create the user interface to the LoginView using the Font Awesome, how to create the LoginViewModel and how to handle the navigation among pages.

Creating the UI using Font Awesome

The Font Awesome supports icons that can be displayed using a Label. That way it is possible to use this font to show an icon in the application. In this step you will use the Microsoft, Google and Facebook icons to display in the UI, this way you do not need to use images.

To start, open the ENEI.SessionsApp project and add a new XAML page in the Views folder, as in the following:



The result will be the following XAML page: 
  1. <?xml version="1.0" encoding="utf-8" ?>  
  2. <ContentPage  
  3.     xmlns="http://xamarin.com/schemas/2014/forms"  
  4.     xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"  
  5.              x:Class="ENEI.SessionsApp.Views.LoginView">  
  6.     <Label Text="{Binding MainText}" VerticalOptions="Center" HorizontalOptions="Center" />  
  7. </ContentPage>  
Now, you can define the user interface, but before that you need to do some additional tasks in each platform to ensure the font will be displayed in the screen when you run the app.

In general you need: 
  • In ENEI.SessionsApp.iOS
Add the FontAwesome.ttf file to the Resources folder as in the following:



Figure: The Resources folder

Change the Info.plist, to include the font.

In Visual Studio or Xamarin Studio it is possible to edit the XML as in the following:
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">  
  3. <plist version="1.0">  
  4.     <dict>  
  5.       
  6.     …  
  7.   
  8.       
  9.         <key>UIAppFonts</key>  
  10.         <array>  
  11.             <string>FontAwesome.ttf</string>  
  12.         </array>  
  13.     </dict>  
  14. </plist>  
In Xamarin Studio you can add the font as in the following:



Figure:
The Source panel from Info.plist in Xamarin Studio

Android

Add the FontAwesome.ttf to the Assets folder as in the following:



Figure: The Assets folder

Create a Render for a CustomLabel
  1. [assembly: ExportRenderer(typeof(CustomLabel), typeof(CustomLabelRenderer))]  
  2. namespace ENEI.SessionsApp.Droid.Renders {  
  3.     public class CustomLabelRenderer: LabelRenderer {  
  4.         protected override void OnElementChanged(ElementChangedEventArgs < Label > e) {  
  5.             base.OnElementChanged(e);  
  6.   
  7.             var label = (TextView) Control;  
  8.             Typeface font = Typeface.CreateFromAsset(Forms.Context.Assets, "FontAwesome.ttf");  
  9.             label.Typeface = font;  
  10.         }  
  11.     }  
  12. }  
In ENEI.SessionsApp.WinPhone or ENEI.SessionsApp.WinRT:
  • Add the FontAwesome.ttf to the Assets/Fonts folder


Figure: The Assets/Folder folder
  • Set the FontAwesome.ttf as Content and Copy Always


Figure: Configurations

In ENEI.SessionsApp
  • Add a CustomLabel class.

  • Define the FontFamily for each platform.
  1. public class CustomLabel: Label {  
  2.     public CustomLabel() {  
  3.         FontFamily = Device.OnPlatform(  
  4.         iOS: "FontAwesome",  
  5.         Android: null,  
  6.         WinPhone: @  
  7.         "\Assets\Fonts\FontAwesome.ttf#FontAwesome");  
  8.   
  9.         if (Device.OS == TargetPlatform.Windows) {  
  10.             FontFamily = @  
  11.             "\Assets\Fonts\FontAwesome.ttf#FontAwesome";  
  12.         }  
  13.     }  
  14. }  
Now you are ready to create the UI for the LoginView. The base for the page can be something as in the following:
  1. <?xml version="1.0" encoding="utf-8" ?>  
  2. <ContentPage  
  3.     xmlns="http://xamarin.com/schemas/2014/forms"  
  4.     xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"  
  5.     xmlns:controls="clr-namespace:ENEI.SessionsApp.Controls;assembly=ENEI.SessionsApp"  
  6.              x:Class="ENEI.SessionsApp.Views.LoginView"  
  7.              Title="Authentication" BackgroundColor="White" x:Name="ContentPage"  
  8.              Icon="ic_action_users.png">  
  9.     <Grid BackgroundColor="White">  
  10.         <Grid.RowDefinitions>  
  11.             <RowDefinition Height="Auto" />  
  12.             <RowDefinition Height="*" />  
  13.         </Grid.RowDefinitions>  
  14.         <!-- Title - Only for WP-->  
  15.         <StackLayout Grid.Row="0" Orientation="Horizontal" Padding="20,10,0,0">  
  16.             <StackLayout.IsVisible>  
  17.                 <OnPlatform Android="false" WinPhone="true" iOS="false"  
  18.                     x:TypeArguments="x:Boolean" />  
  19.             </StackLayout.IsVisible>  
  20.             <Image WidthRequest="48"  
  21.              HeightRequest="38"  
  22.              Source="Images/ic_action_users.png"/>  
  23.             <Label FontSize="Medium" FontAttributes="Bold"  
  24.            TextColor="Black">  
  25.                 <OnPlatform Android="" WinPhone="Authentication"  
  26.                     iOS="" x:TypeArguments="x:String" />  
  27.             </Label>  
  28.         </StackLayout>  
  29.         <StackLayout Spacing="20" HorizontalOptions="Center" VerticalOptions="CenterAndExpand" Grid.Row="1">  
  30.             <!—login by social network will be here -->  
  31.         </StackLayout>  
  32.     </Grid>  
  33. </ContentPage>  
Then you can define options for login with Facebook, Google or Microsoft as in the following:

Facebook

  1. <StackLayout WidthRequest="300" HeightRequest="60" Orientation="Horizontal" BackgroundColor="#3b5998" HorizontalOptions="Center" Spacing="20">  
  2.     <controls:CustomLabel FontSize="Small"  
  3.                             HorizontalOptions="CenterAndExpand"  
  4.                             Text=""  
  5.                             TextColor="White"  
  6.                             VerticalOptions="CenterAndExpand" />  
  7.     <Label FontAttributes="Bold"  
  8.                 FontSize="Small"  
  9.                 HorizontalOptions="StartAndExpand"  
  10.                 Text="Facebook"  
  11.                 TextColor="White"  
  12.                 VerticalOptions="CenterAndExpand" />  
  13. </StackLayout>  
Google
  1. <StackLayout WidthRequest="300" HeightRequest="60"  Orientation="Horizontal" BackgroundColor="#dd4b39" HorizontalOptions="Center" Spacing="20">  
  2.     <controls:CustomLabel FontSize="Small"  
  3.                               HorizontalOptions="CenterAndExpand"  
  4.                               Text=""  
  5.                               TextColor="White"  
  6.                               VerticalOptions="CenterAndExpand" />  
  7.     <Label FontAttributes="Bold"  
  8.                 FontSize="Small"  
  9.                 HorizontalOptions="StartAndExpand"  
  10.                 Text="Google"  
  11.                 TextColor="White"  
  12.                 VerticalOptions="CenterAndExpand" />  
  13. </StackLayout>  
Microsoft
  1. <StackLayout WidthRequest="300" HeightRequest="60"  Orientation="Horizontal" BackgroundColor="#219dfd" HorizontalOptions="Center" Spacing="20">  
  2.     <controls:CustomLabel FontSize="Small"  
  3.                            HorizontalOptions="CenterAndExpand"  
  4.                            Text=""  
  5.                            TextColor="White"  
  6.                            VerticalOptions="CenterAndExpand" />  
  7.     <Label FontAttributes="Bold"  
  8.                FontSize="Small"  
  9.                HorizontalOptions="StartAndExpand"  
  10.                Text="Microsoft"  
  11.                TextColor="White"  
  12.                VerticalOptions="CenterAndExpand" />  
  13. </StackLayout>  
  14.      
When you run the application the result will something as described below.



Figure: The LoginView

Create the LoginViewModel

At this moment, you have the user interface to the LoginView, this way it is possible to define the LoginViewModel, that will have the action for each option in LoginView.

Open the ENEI.SessionsApp project and add the LoginViewModel to the ViewModels folder, as in the following:



Figure: The LoginViewModel

Then create the LoginCommnad, as in the following:
  1. public class LoginViewModel {  
  2.     public LoginViewModel() {  
  3.         LoginCommand = new Command(DoLogin);  
  4.     }  
  5.   
  6.     private void DoLogin(object param) {  
  7.         var option = param.ToString();  
  8.         switch (option) {  
  9.             case "facebook":  
  10.                 //connect with facebook api  
  11.                 break;  
  12.             case "goolge":  
  13.                 //connect with google api  
  14.                 break;  
  15.             case "microsoft":  
  16.                 //connect with microsoft api  
  17.                 break;  
  18.         }  
  19.     }  
  20.   
  21.     public ICommand LoginCommand {  
  22.         get;  
  23.         set;  
  24.     }  
  25. }  
In this case, you only created one ICommand that will be used be all options in the LoginView and for that it is necessary to send a CommandParameter the name of the option, as we will see next.

Now, connect the UI with the LoginViewModel and to start, define the LoginViewModel and binding it to the BindingContext as in the following:
  1. public partial class LoginView: ContentPage {  
  2.     public LoginView() {  
  3.         InitializeComponent();  
  4.         BindingContext = new LoginViewModel();  
  5.     }  
  6. }  
Then change the StackLayout that is the root for each option as in the following:
  1. <StackLayout WidthRequest="300" HeightRequest="60" Orientation="Horizontal" BackgroundColor="#3b5998" HorizontalOptions="Center" Spacing="20">  
  2.     <StackLayout.GestureRecognizers>  
  3.         <TapGestureRecognizer CommandParameter="facebook"  
  4.                                     Command="{Binding LoginCommand}"/>  
  5.     </StackLayout.GestureRecognizers>  
  6.     <controls:CustomLabel FontSize="Small"  
  7.                             HorizontalOptions="CenterAndExpand"  
  8.                             Text=""  
  9.                             TextColor="White"  
  10.                             VerticalOptions="CenterAndExpand" />  
  11.     <Label FontAttributes="Bold"  
  12.                 FontSize="Small"  
  13.                 HorizontalOptions="StartAndExpand"  
  14.                 Text="Facebook"  
  15.                 TextColor="White"  
  16.                 VerticalOptions="CenterAndExpand" />  
  17. </StackLayout>  
Do a similar implementation to the others option.

When you run the application you should call the DoLogin method, as in the following:



Figure: The DoLogin method in debug mode

Handle the navigation

At this moment you do not have the authentication, but you can create the complete flow to the application. This way, you need to define the navigation among pages, that is the main goal of this step.

To start, you can create a NavMessage, as in the following:
  1. public class NavMessage {  
  2.     public string Page {  
  3.         get;  
  4.         set;  
  5.     }  
  6.   
  7.     public object Param {  
  8.         get;  
  9.         set;  
  10.     }  
  11. }  
Then, in the App class you can use MessaginCenter to navigate among pages, as in the following:
  1. public App()   
  2. {  
  3.     InitializeComponent();  
  4.     MainPage = new NavigationPage(new LoginView()) {  
  5.         BarBackgroundColor = Color.White,  
  6.         BarTextColor = Color.Black,  
  7.         BackgroundColor = Color.White,  
  8.     };  
  9.   
  10.     MessagingCenter.Subscribe < NavMessage > (this"Navigation", navMessage = > {  
  11.         switch (navMessage.Page) {  
  12.             case "login":  
  13.                 MainPage = new LoginView();  
  14.                 break;  
  15.             case "sessions":  
  16.                 MainPage = new NavigationPage(new SessionsView()) {  
  17.                     BarBackgroundColor = Color.White,  
  18.                     BarTextColor = Color.Black,  
  19.                     BackgroundColor = Color.White,  
  20.                 };  
  21.                 break;  
  22.             case "details":  
  23.                 MainPage.Navigation.PushAsync(new SessionDetailsView(navMessage.Param as Session), true);  
  24.                 break;  
  25.         }  
  26.     });  
  27. }  
There are various ways to handle the navigation and it can be defined based on the application requirements.

In the LoginViewModel you should change the DoLogin method to:
  1. private void DoLogin(object param) {  
  2.     var option = param.ToString();  
  3.     switch (option) {  
  4.         case "facebook":  
  5.             //connect with facebook api  
  6.             break;  
  7.         case "goolge":  
  8.             //connect with google api  
  9.             break;  
  10.         case "microsoft":  
  11.             //connect with microsoft api  
  12.             break;  
  13.     }  
  14.     MessagingCenter.Send(new NavMessage {  
  15.         Page = "sessions"  
  16.     }, "Navigation");  
  17. }  
At this moment the authentication is not important, because that feature will be dealt with in the next steps.

In the SessionsViewModel change the SeeSessionDetails method to:
  1. private void SeeSessionDetails(object param)  
  2. {  
  3.     var session = param as Session;  
  4.     if (session != null)  
  5.     {  
  6.        MessagingCenter.Send(new NavMessage  
  7.        {  
  8.           Page = "details",  
  9.           Param = session  
  10.        }, "Navigation");  
  11.     }  
  12. }  
And, in the SessionsView remove the navigation, that result should be:
  1. public SessionsView()  
  2. {  
  3.     InitializeComponent();  
  4. }  
At this moment if you run the application you should start in the LoginView and then you can see the SessionsView and the SessionDetailsView.