Please note, this does not mean that we want to make the same exact UI for Android, iOS and Windows Phone. In fact that would produce a substandard user experience. But to the extent possible, it's isn't the syntax that matters, only appearance and behavior. Xamarin.Forms gives us a much greater possibility of sharing UI code across platforms than ever before while still maintaining a native experience.
For the most part I don't think we are going to be using Xamarin.Forms for a lot of applications that we would have considered using complex native UIs a few months ago because there are going to be some platform specific tweaks that are still going to demand a native design experience. But that's OK because in such an application you can mix Xamarin.Forms for the more generic native experiences in the application with native forms where we need to do something very platform specific.
So where does that leave Xamarin.Forms? Its sweet spot would seem to be when we may have considered using a hybrid tool like PhoneGap or Appcellerator for cross platform development. Because Xamarin.Forms still produces a native UI it will produce a much better native experience for the user while giving us all the cross platform UI code sharing that we would get from these tools. It would seem to be a far superior choice and extremely compelling.
I wanted to try this out. Xamarin has an introduction that I found useful here:
http://developer.xamarin.com/guides/cross-platform/xamarin-forms/introduction-to-xamarin-forms/
It is day two of playing around with this for me and let me tell you Xamarin.Forms seems vast, very vast. There is a lot to learn here and I look forward to attending next weeks Xamarin University class on Xamarin.Forms. It is going to take a bit of time to really learn how to use it well. For my first project I wanted to use actual XAML files and also use the new Universal Application Shared Projects. For many reasons I believe this will be a better approach for most cross platform projects than using a PCL.
Here's what I did:
Step 1: Install Xamarin 3.0. Just use the normal update process, no magic here.
Step 2: Create a new solution with projects for the platform specific UIs we want to support. For my solution I selected an Android Application and an iOS empty Universal Application.
Step 3: Add a Xamarin.Forms project. A Xamarin.Forms project is a project that provides shared code to the Android and iOS projects we just created. This can be accomplished by using a portable class library or the new universal shared application. Unfortunately in Visual Studio there are only three templates currently available under the Mobile Apps section. One is used to create a multi-project solution with shared code through a portable class library, one to create a multi-project solution using a universal application shared project and one to create a new Xamarin.Form portable class library on it's own. There is currently no template to create a Universal Application Shared Xamarin.Forms project on its own. Luckily this is possible using the Universal Application Extension. With this extension I created a new Universal Application Shared Project for my Xamain.Forms that I want to share with both projects and then put my Xamarin.Forms code in there.
Step 4: Add a reference to the Xamarin.Forms project to our iOS and Android projects. This can be done by right clicking on references and selecting Add Nuget Package. Search for the Xamarin.Forms project and add it. Also add a Shared Project Reference for the new Universal Application Shared Project in the iOS and Android projects.
Step 5: Add a new Forms XAML Page to the Shared Project we created. I called mine SharedForm.xaml.
Note: When I try to open the XAML file I get a designer error but I am still able to edit the XAML directly. From the Xamain.Forms forum on the Xamarin site it looks like there is currently no visual designer for this. It was strongly hinted that one is in the works however. I added a label and a button to make a very simple form that I called SharedForm.xaml. The following is the code in my XAML file:
<?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="XamarinFormsTest.Shared.SharedForm"> <StackLayout Spacing="10"> <Label Text="Foo" VerticalOptions="Center" HorizontalOptions="Center" /> <Button Text="Bar" x:Name="btnBar" /> </StackLayout> </ContentPage>
Step 6: I want to show a popup window of some sort when they click on my new "bar" button. It wouldn't surprise me to learn there is some sort of cross platform library for this in Xamarin.Forms but I don't know what it is. Instead I used a Toast for Android and a UIAlertView for iOS. This is where using a Universal Application Shared Project really shines. Using the a conditional compilation symbol of __Android__ in the Android project and __IOS__ in the iOS project I was able to do the following:
1: public partial class SharedForm : ContentPage
2: {
3: public SharedForm ()
4: {
5: InitializeComponent();
6: btnBar.Clicked += btnBar_Click;
7: }
8:
9: private void btnBar_Click(object sender, EventArgs e)
10: {
11: #if __ANDROID__
12: Android.Widget.Toast.MakeText(Android.App.Application.Context, "Test 123", Android.Widget.ToastLength.Short).Show();
13: #elif __IOS__
14: new MonoTouch.UIKit.UIAlertView("Test", "Test 123", null, "Ok", null).Show();
15: #endif
16: }
17: }
I also tied the click event of the button to a new method, btnBar_Click. If we are compiled into the Android application the Toast message is used in the method, otherwise the UIAlertView is used for iOS.
Step 7: I went into the android project's main activity and changed it so it inherits from AndroidActivity instead of Activity. I also made a call to Forms.Init() and created a new instance of my SharedFrom. A quick call to SetPage and my XAML form is used.
1: [Activity(Label = "XamarinFormsTest", MainLauncher = true, Icon = "@drawable/icon")]
2: public class MainActivity : AndroidActivity
3: {
4: protected override void OnCreate(Bundle bundle)
5: {
6: base.OnCreate(bundle);
7:
8: Xamarin.Forms.Forms.Init(this, bundle);
9:
10: var form = new SharedForm();
11: SetPage(form);
12: }
13: }
When I run the application and click on the "Bar" button this is what I see:
Step 8: I want to try the same thing for iOS. So I go to the iOS project's AppDelegate. In the FinishedLaunching event I again call Forms.Init() and then create an instance of my XAML form. On the form there is a CreateViewController() method that I call to set the window's RootViewController.
1: public override bool FinishedLaunching(UIApplication app, NSDictionary options)
2: {
3: // create a new window instance based on the screen size
4: window = new UIWindow(UIScreen.MainScreen.Bounds);
5:
6: // If you have defined a view, add it here:
7: // window.RootViewController = navigationController;
8: Forms.Init();
9:
10: var form = new SharedForm();
11: window.RootViewController = form.CreateViewController();
12:
13: window.MakeKeyAndVisible();
14:
15: return true;
16: }
I then run the project on the iOS simulator, click on the "Bar" button and this is what I see there:
Similar but different. I used the same UI syntax for a button and in one case I got an android button and here I got an iOS 7 style button, nice and flat. Granted this was a simple example and it looks like my label got a bit mixed up with text at the top of the iOS simulator. There is clearly more experimentation and learning I need to do. But the idea seems to work. Almost all of my code was shared and I was able to do it with little fuss or muss.
Very exciting and I'm ready to learn more.