[Cross Platform] Introducción a Xamarin.Forms (1/2)

Introducción

No hay duda, los smartphones han llegado, y ya forman parte de la
vida de todos nosotros. En muchos aspectos de nuestra vida accedemos a
información, realizamos algna tarea o sencillamente nos entretenemos con
uno de ellos.

Esto también nos afecta como desarrolladores. El desarrollo móvil se
ha convertido en una prioridad en una gran mayoria de ámbitos.

Actualmente contamos con varias plataformas dominantes:

  • iOS
  • Android
  • Windows Phone

Esto a nivel de desarrollo nos supone barreras. Contamos con
plataformas de desarrollo diferentes, lenguajes diferentes, etc.
suponiendo un nivel de aprendizaje y esfuerzo cada vez mayor de cara a
desarrolladores. Además, la experiencia nos ha demostrado que los
usuarios no aceptan aplicaciones no nativas. Los usuarios buscan aplicaciones rápidas, fluidas y con
consumos moderados, perfectamente adaptadas a la plataforma ofreciendo
una experiencia completa.

¿Qué podemos hacer para mejorar este panorama?

Xamarin.Forms

Con la reciente actualización a la versión 3 de Xamarin nos llega Xamarin.Forms. Es un toolkit para crear una abstracción sobre la interfaz de usuario de Android, iOS y Windows Phone permitiendo desarrollarla una única vez con código C# o Extensible Application Markup Language (XAML).

Xamarin.Forms nos permite crear aplicaciones para:

  • Android 4.0 o superior
  • iOS 6.1 o superior
  • Windows Phone 8.0

NOTA: Fijáos que hablamos de Windows Phone 8.0
con Silverlight. Incluso necesitamos usar el Toolkit de Windows Phone
para poder tener acceso a ciertos controles como por ejemplo el
DatePicker o a animaciones.

Nuestra primera aplicación Xamarin.Forms

Una vez instalada la versión 3 de Xamarin tendremos acceso a las nuevas soluciones Xamarin.Forms:

Contamos con las siguientes opciones:

  • Aplicación con Librería Portable: Crea una solución con un proyecto para cada plataforma junto a una librería portable donde añadir el código compartido.
  • Aplicación con proyecto Shared: Crea una solución
    con un proyecto para cada paltaforma junto a un cuarto proyecto Shared.
    Muy similar al concepto de aplicación universal en Windows Phone 8.1.
  • Librería portable: Crea una librería portable.

Creamos una aplicación con proyecto Shared.Contamos con la siguiente estructura de solución:

Por defecto se nos crea una aplicación de ejemplo muy básica con una única vista y un saludo en medio.

Analicemos el código fuente de la plantilla antes de continuar. La aplicación generada cuenta con una única página de tipo Xamarin.Forms.Page
que representa un Activity en Android, un View Controller en iOS y una
Page en Windows Phone. El tipo de página utilizada (posteriormente
veremos que contamos en Xamarin.Forms con múltiples tipos de páginas) es
Xamarin.Forms.ContentPage que cuenta con un Label como contenido.

En el proyecto compartido contamos con una clase llamada App. Esta
clase es la responsable de indicar cual sera la primera página a mostrar
en todas las plataformas.

public class App
{
    public static Page GetMainPage()
    {
        return new ContentPage
        {
            Content = new Label
            {
                Text = "Hello, Forms !",
                VerticalOptions = LayoutOptions.CenterAndExpand,
                HorizontalOptions = LayoutOptions.CenterAndExpand,
            },
        };
    }
}

En el caso por defecto, se crea con C# una instancia nueva de una
página de contenido y se le añade un Label centrado en pantalla.
Sencillo, ¿verdad?.

Una vez creada la página, en cada plataforma se debe:

  • Inicializar Xamarin.Forms
  • Proveer la página de contenido

Windows Phone

Debemos incializar Xamarin.Forms que lo haremos utilizando Forms.Init() además de establecer como contenido de la página nuestra Xamarin.Forms.ContentPage creada en App:

public partial class MainPage : PhoneApplicationPage
{
    public MainPage()
    {
        InitializeComponent();
 
        Forms.Init();
        Content = HelloXamarinFormsWorld.App.GetMainPage().ConvertPageToUIElement(this);
    }
}

Android

Con el MainLauncher creamos un Activity como en una aplicación normal Android, exceptuando que nuestro Activity hereda de Xamarin.Forms.Platform.Android.AndroidActivity. En el método OnCreate inicializamos Xamarin.Forms y establecemos nuestra página.

namespace HelloXamarinFormsWorld.Android
{
    [Activity(Label = "HelloXamarinFormsWorld", MainLauncher = true)]
    public class MainActivity : AndroidActivity
    {
        protected override void OnCreate(Bundle bundle)
        {
            base.OnCreate(bundle);
 
            Xamarin.Forms.Forms.Init(this, bundle);
 
            SetPage(App.GetMainPage());
        }
    }
}

iOS

Por último,  en iOS, la clase AppDelegate inicializará Xamarin.Forms y establecerá el RootViewController a nuestra ContentPage de la clase App.

[Register("AppDelegate")]
public partial class AppDelegate : UIApplicationDelegate
{
    UIWindow window;
 
    public override bool FinishedLaunching(UIApplication app, NSDictionary options)
    {
        Forms.Init();
 
        window = new UIWindow(UIScreen.MainScreen.Bounds);
 
        window.RootViewController =  App.GetMainPage().CreateViewController();
 
        window.MakeKeyAndVisible();
 
        return true;
    }
}

Creando una App con C#

Hasta ahora hemos visto que Xamarin.Forms nos permite crear la
interfaz dde usuario de Windows Phone, Android e iOS de manera
compartida usando C# o XAML y hemos analizado el proyecto base creado
con las plantillas.

Continuamos profundizando cada vez más en Xamarin.Foms, vamos a crear
una primera aplicación sencilla utilizando el patrón MVVM y diseñando
la interfaz de usuario con C#.

Vamos a crear una aplicación que cuente con un botón, que al ser
pulsado ejecute  un comando en la viewmodel y actualice un texto con el
número de veces que el botón ha sido pulsado. Simple, pero suficiente
para ver muchos conceptos básicos.

Creamos un nuevo proyecto con la plantilla Blank App (Xamarin.Forms Shared). En el proyecto Shared creamos las carpetas:

  • Views
  • ViewModels

Dentro de la carpeta ViewModels, añadimos una carpeta Base donde vamos a añadir algunas clases base importantes para cubrir todas nuestras necesidades. Comenzamos añadiendo un ViewModelBase que se encargará de:

  • Notificar cambios
  • Notificar el estado
public abstract class ViewModelBase : INotifyPropertyChanged
{
     private Frame _appFrame;
     private bool _isBusy;
 
     public Frame AppFrame
     {
            get { return _appFrame; }
     }
 
     public bool IsBusy
     {
         get { return _isBusy; }
         set
         {
             _isBusy = value;
             RaisePropertyChanged();
         }
     }
 
     public event PropertyChangedEventHandler PropertyChanged;
 
     public void RaisePropertyChanged([CallerMemberName]string propertyName = "")
     {
         var Handler = PropertyChanged;
         if (Handler != null)
             Handler(this, new PropertyChangedEventArgs(propertyName));
     }
 
     internal void SetAppFrame(Frame viewFrame)
     {
         _appFrame = viewFrame;
     }
}

De esta clase heredarán todos nuestros viewmodels. Además, añadiremos otra clase importante, DelegateCommand.

Añadimos una nueva clase, llamada MainViewModel en nuestra carpeta ViewModels. Por supuesto, añadimos también otra clase llamada MainView que será la vista principal de nuestra aplicación, en la carpeta Views.

Comenzamos creando la vista de nuestra aplicación en C# (MainView).

public class MainView : ContentPage
{
 
}

Como podemos ver, nuestra clase hereda de ContentPage. En Xamarin.Forms contamos con distintos tipos de páginas:

  • ContentPage: Página de contenido que cuenta con una única vista donde añadir contenido.
  • MasterDetailPage: Página que gestiona dos paneles de información (maestro-detalle).
  • NavigationPage: Una página que gestiona una pila de otras páginas, la navegación y la experiencia de usuario entre ellas.
  • TabbedPage: Una página que permite el accesoa las subpáginas mediante tabs.
  • CarouselPage: Una página que permite acceder a las subpáginas haciendo un gesto de swipe (scroll lateral).

En nuestro ejemplo, elegimos la página más simple, ContentPage. A
continuación empezamos a añadir el contenido de nuestra página:

//Contenedor principal
var stack = new StackLayout
{
     Orientation = StackOrientation.Vertical,
     Padding = new Thickness(0, 10)
};

Comenzamos por un contenedor. El StackLayout es
un control de tipo contenedor, su cometido es organizar y posicionar
otros controles. Apila los controles por defecto verticalmente aunque
podemos controlar si apilamos de forma vertical o horizontal.

Contamos con múltiples controles de tipo contenedor aparte del StackLayout:

  • ScrollView: Contenedor que permite realizar scroll si el contenido lo requiere.
  • AbsoluteLayout: Posiciona los elementos mediante posiciones absolutas.
  • Grid: Contenedor potente que organiza los elementos mediante filsa y columnas.
  • RelativeLayout: Posiciona los elementos mediante constrainsts.

Continuamos con nuestro ejemplo, añadimos un texto informativo:

//Texto informativo
var info = new Label
{
     Font = Font.SystemFontOfSize(NamedSize.Medium),
     Text = "Hola Xamarin Forms!",
     LineBreakMode = LineBreakMode.WordWrap
};

Hemos añadido un control Label. Tras añadirlo, lo incluimos dentro de nuestro panel:

//Añadimos un botón. Al pulsarlo, actualizará el número de veces que lo pulsamos
var button = new Button
{
     Text = "Púlsame!"  
};
 
//Añadimos el botón a nuestro contenedor
stack.Children.Add(button);
 
var result = new Label
{
     Font = Font.SystemFontOfSize(NamedSize.Large)
};
 
//Añadimos el texto a nuestro contenedor
stack.Children.Add(result);

Hasta aquí toda nuestra inferfaz casi lista!. Nos faltan detalles
sumamente importantes como gestionar la lógica del botón al hacer clic.
En nuestra viewmodel:

public class MainViewModel : ViewModelBase
{
     private int _clicCounter;
 
     private DelegateCommand _helloCommand;
 
     public MainViewModel()
     {
         _clicCounter = 0;
     }
 
     public string Message
     {
         get { return string.Format("Botón pulsado {0} veces", _clicCounter); }
     }
 
     public ICommand HelloCommand
     {
         get { return _helloCommand = _helloCommand ?? new DelegateCommand(HelloCommandDelegate); }
     }
 
     private void HelloCommandDelegate()
     {
         _clicCounter++;
         RaisePropertyChanged("Message");
     }
}

Añadimos un comando que aumentará un contador que nos indicará las veces que se ha pulsado el botón y actualizará un mensaje.

Data Binding

Al igual que en el desarrollo de Windows Phone, el Data binding lo
usamos en Xamarin.Forms para mostrar e interactuar con la información.
Básicamente, establecemos un vínculo entre la interfaz de usuario y la
lógica de la aplicación.

En nuestro ejemplo, queremos vincular nuestra vista, MainView, con
nuestra viewmodel, MainViewModel. Para ello, utilizaremos la propiedad BindingContext:

// DataContext de la página, nuestro ViewModel
BindingContext = new MainViewModel();

Creamos también una propiedad de la viewmodel para que nuestra vista tenga acceso a propiedades y comandos de la viewmodel:

private MainViewModel ViewModel
{
     get { return BindingContext as MainViewModel; }
}

Nos faltaba establecer el comando HelloCommand de nuestra viewmodel al botón de nuestra interfaz:

var button = new Button
{
     Text = "Púlsame!",
     Command = ViewModel.HelloCommand
};

Por último, nos faltaba también añadir al segundo Label de la interfaz, el binding a la propiedad Message:

result.SetBinding(Label.TextProperty, "Message");

Utilizamos el método SetBinding. Este método espera dos parámetros:

El primer parámetro espera información sobre la propiedad en la que estableceremos el binding.

La segunda propiedad espera información sobre el binding. En la
mayoría de situaciones será una cadena con el nombre de la propiedad a
bindear del BindingContext.

Podéis descargar el ejemplo realizado a continuación:

Ahora con XAML!

Pues si, como ya hemos mencionado, podemos crear la interfaz de
usuario utilizando C# o XAML. El ejemplo exactamente igual que el
anterior pero trasladado a XAML. Para ello, en la carpeta Views, vamos a
añadir una Forms XAML Page. Clic derecho, añadir nuevo elemento:

<?xml version="1.0" encoding="utf-8" ?>
                       xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                       x:Class="HolaXamarinFormsXAML.Views.MainView">
</ContentPage>

Añadimos nuestro contenedor junto a nuestros Labels y el botón:

<?xml version="1.0" encoding="utf-8" ?>
                       xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                       x:Class="HolaXamarinFormsXAML.Views.MainView">
    <StackLayout Orientation="Vertical" Padding="0, 10">
        <Label Text="Hola Xamarin Forms!" />
        <Button Text="Púlsame!"  />
        <Label />
    </StackLayout>
</ContentPage>

Por último, establecemos los bindings:

<?xml version="1.0" encoding="utf-8" ?>
                       xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                       x:Class="HolaXamarinFormsXAML.Views.MainView">
    <StackLayout Orientation="Vertical" Padding="0, 10">
        <Label Text="Hola Xamarin Forms!" />
        <Button Text="Púlsame!" Command="{Binding HelloCommand}" />
        <Label Text="{Binding Message}" />
    </StackLayout>
</ContentPage>

Al botón le bindeamos el comando HelloCommand y al segundo Label el
mensaje resultante. Como podemos ver, la forma de establecer bindings es
igual al utilizado en XAML de Windows Phone por ejemplo.

Podéis descargar el ejemplo realizado a continuación:

Llegando más lejos

Hasta ahora hemos visto bastantes detalles de Xamarin.Forms pero nos
queda aun camino por recorrer. Una aplicación con acceso a
características del sistema, múltiples páginas, ver como gestionar esto,
inyectar servicios entre otros puntos. Todo lo anterior lo veremos en
la continuación de este artículo.

Más información

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *