[Xamarin.Forms] Introducción al uso de efectos

Introducción

Xamarin.Forms añade una capa de abstracción sobre la capa de la interfaz de usuario permitiendo definir la misma una única vez siendo válida para todas las plataformas.

Xamarin.Forms
Xamarin.Forms

Cuenta con páginas, layouts y controles que son renderizados de forma diferente en cada plataforma. Se utiliza una clase Renderer distinta en cada plataforma y encargada de crear un control nativo y añadirlo en pantalla.

¿Qué es un efecto?

Un efecto permite el acceso al control nativo de cada plataforma con el objetivo de personalizarlo, principalmente aplicando pequeños cambios estéticos o de comportamiento. Permiten simplificar la personalización del control y sobretodo se convierten en «piezas» reutilizables de código incluso aceptando parametrización.

¿Por qué usar efectos y no un Custom Renderer?

Tener acceso a un control nativo, poder personalizarlo y además tenerlo todo en una pieza reutilizable está al alcance de nuestra mano gracias al uso de efectos.

¿Cuándo utilizamos entonces un Custom Renderer, y cuándo un efecto?

  • Si necesitamos crear un nuevo control o  reemplazar el control específico implementado por Xamarin.Forms de una plataforma, necesitamos un Custom Renderer.
  • Si sólo necesitamos modificar o añadir alguna propiedad que modifica la apariencia o comportamiento del control nativo implementado por Xamarin.Forms, efecto.

Crear un efecto

El proceso de creación de un efecto, se puede resumir en una serie de sencillos pasos:

  1. Crear en la PCL una clase que herede de RoutingEffect. Código independiente de la plataforma encargado de hacer el wrapping del efecto. Podemos definir distintas propiedades que permitan modificar la acción realizada por el efecto. Por ejemplo, en un efecto encargado de aplicar Blur a una imagen, se puede definir una propiedad encarga de aplicar mayor o menor distorsión.
  2. Crear clases en cada plataforma soportada que hereden de PlatformEffect.
  3. Sobrecargar el método OnAttached y añadir la lógica de personalización del control.
  4. Sobrecargar el método OnDetached y añadir lógica de liberación de recursos.
  5. Añadir el atributo ResolutionGroupName. Este atributo permite establecer el nombre del creador o compañia tras el efecto. Recuerda que uno de los objetivos fundamentales de los efectos es lograr permitir compartir y reutilizar con suma facilidad. Con este atributo se previenen colisiones con otros efectos que compartan nombre.
  6. Añadir el atributo ExportEffect. Este atributo registra el efecto con un identificador único usado por Xamarin.Forms, junto al nombre del grupo, permite localizar y aplicar el efecto.

Para comprender el proceso de creación de un efecto vamos a crear uno paso a paso. Nuestro efecto será simple, permitirá aplicar el efecto blur a una imagen.

Comenzamos en la PCL. Dentro de la carpeta Effects, creamos una clase que herede de RoutingEffect:

public class BlurredEffect : RoutingEffect
{
     public string Url { get; set; }
     public int Radius { get; set; }

     public BlurredEffect() : base("Xamarin.BlurredImageEffect")
     {

     } 
}

Además de la implementación del constructor, donde indicamos el nombre del grupo y del efecto que utilizaremos en la implementación de cada plataforma, añadimos dos propiedades:

  • Url: La Url de la imagen a la que aplicaremos el efecto.
  • Radius: Un entero que permite establecer el nivel de distorsión aplicado. A valores más altos, mayor nivel de distorsión.

Tras la creación de la «definición» de lo que será nuestro servicio, pasamos al código específico por plataforma. Se deben de crear clases que hereden de PlatformEffect:

public class BlurredImageEffect : PlatformEffect  
{

}

PlatformEffect provocará la necesidad de implementar los métodos OnAttached y OnDetached:

protected override void OnAttached() 
{

}

protected override void OnDetached()    
{
        
}

Vamos a comprender el objetivo de cada método:

  • OnAttached: Lanzado cuando un efecto se adjunta un control Xamarin.Forms. La sobrecarga de este método en cada plataforma es el lugar idóneo para añadir código específico de plataforma que afecte al control ya sea en su apariencia o en su comportamiento.
  • OnDetached: Este método se lanza cuando el efecto se quita del control Xamarin.Forms. La sobrecarga permite añadir código específico de liberación de recursos y limpieza.

Aunque no lo usamos en nuestro efecto de blur, PlatformEffect expone el método OnElementPropertyChanged. Este método se lanza cuando una propiedad del efecto cambia. Lugar idóneo para responder a cambios de la propiedades.

Implementamos el código del método OnAttached en Android:

protected override void OnAttached()
{
     try
     {
          var imageView = Control as ImageView;
          var effect = (BlurredEffect)Element.Effects.FirstOrDefault(e => e is BlurredEffect);
          if (effect != null)
          {
               var d = imageView.Drawable;
               if (d != null)
               {
                    var bitmap = GetImageBitmapFromUrl(effect.Url);

                    if (bitmap != null)
                    {
                        imageView.SetImageBitmap(CreateBlurredImage(effect.Radius, bitmap));
                        imageView.Invalidate();
                    }
                }
          }
     }   
     catch (Exception ex)
     {
          Console.WriteLine("Cannot set property on attached control. Error: ", ex.Message);
     }
}

Cada clase específica de plataforma que hereda de PlatformEffect cuenta con:

  • Control: Control nativo usado por Xamarin.Forms como implementación del control Xamarin.Forms. Por ejemplo, en Android en el caso de una Image, hablaríamos de un ImageView.
  • Element: Control Xamarin.Forms renderizado.

Analicemos el código anterior. Comienza accediendo al efecto, disponible en la colección Effects del control representado por Element.

Tras acceder al efecto, se crea un Bitmap partiendo de la Url recibida como parámetro en la propiedad Url, y se aplica el efecto Blur utilizando la imagen anterior y aplicando el grado de distorsión utilizando la propiedad Radius.

El método encargado de crear el Bitmap en base a la Url:

prprivate Bitmap GetImageBitmapFromUrl(string url)   
{            
     Bitmap imageBitmap = null;
          
     using (var webClient = new WebClient())
     {
          var imageBytes = webClient.DownloadData(url);
          if (imageBytes != null && imageBytes.Length > 0)
          {
               imageBitmap = BitmapFactory.DecodeByteArray(imageBytes, 0, imageBytes.Length);
          }
     }

     return imageBitmap;
}

Utiliza un WebClient para descargar la información de la imagen y BitmapFactory para crear el Bitmap usando los datos descargados.

El método encargado de aplicar el efecto Blur:

private Bitmap CreateBlurredImage(int radius, Bitmap originalBitmap)
{
     Bitmap blurredBitmap;
     blurredBitmap = Bitmap.CreateBitmap(originalBitmap);

     var rs = RenderScript.Create(Forms.Context);
     var input = Allocation.CreateFromBitmap(rs, originalBitmap, Allocation.MipmapControl.MipmapFull, AllocationUsage.Script);
     var output = Allocation.CreateTyped(rs, input.Type);

     var script = ScriptIntrinsicBlur.Create(rs, Android.Renderscripts.Element.U8_4(rs));
     script.SetInput(input);
     script.SetRadius(radius);
     script.ForEach(output);

     output.CopyTo(blurredBitmap);

     return blurredBitmap;
}

Basado en RenderScript para aplicar el efecto.

Nos faltaría aplicar las etiquetas que permitan establecer el nombre del grupo y la exportación del efecto:

[assembly: ResolutionGroupName("Xamarin")]
[assembly: ExportEffect(typeof(BlurredImageEffect), "BlurredImageEffect")]

De igual forma, en otras plataformas (iOS y Windows) se debe de crear la clase e implementar PlatformEffect.

Utilizar un efecto

Desde la PCL, en la vista compartida definida en XAML, para utilizar el efecto se debe utilizar el espacio de nombre donde se ha definido:

xmlns:effects="clr-namespace:BlurImageEffect.Effects"

Y utilizarlo:

<Label 
     Text="Image"/>
<Image
     Source="https://www.xamarin.com/content/images/pages/branding/assets/xamarin-logo.png"/>
<Label 
      Text="Blurred Image"/>
<Image>
     <Image.Effects>
        <effects:BlurredEffect
             Url="https://www.xamarin.com/content/images/pages/branding/assets/xamarin-logo.png"
             Radius="20"/>
     </Image.Effects>
</Image>

El efecto BlurredEfect se adjunta a la segunda imagen añadiéndolo a la colección Effects. Xamarin.Forms utilizará Effect.Resolve para devolver el efecto especificado utilizando una concatenación del nombre de grupo (ResolutionGroupName) junto a su identificador (especificado con el atributo ExportEffect).

El resultado:

BlurredImageEffect
BlurredImageEffect

Tenéis el código fuente del ejemplo utilizado disponible en GitHub:

Ver GitHub

Recuerda, cualquier tipo de duda o sugerencia es bienvenida en los comentario del artículo.

Más información

[Evento SVQXDG] Xamarin Dev Days en Sevilla!

XamarinEl evento

Xamarin Dev Days son una serie de eventos celebrados a lo largo de todo el mundo que ofrecen la posibilidad de conocer las últimas novedades relacionadas con el desarrollo Xamarin, poder disfrutar de talleres y por supuesto, compartir momentos de networking.

Xamarin Dev Days
Xamarin Dev Days

La agenda:

• 9:00AM Registro y bienvenida.

• 9:30 – 10:10AM Introducción a Xamarin. Introducción a los conceptos básicos tanto de Xamarin Classic como de Xamarin.Forms así como a la integración con Visual Studio, Xamarin Test Cloud, etc. Por Josué Yeray.

• 10:20 – 11:00AM Xamarin Forms. Tras una introducción a conceptos básicos se verá como estructurar el proyecto y una serie de buenas prácticas para compartir la mayor cantidad de código posible. Finalmente se terminará con las últimas novedades como Xamarin.Forms Previewer, DataPages, Themes o Native Embedding. Por Javier Suárez.

• 11:10 – 11:50AM Xamarin + Azure. Gracias al Azure podemos crear servicios de backend, notificaciones push y otras características esenciales de forma compartida. En esta sesión aprenderemos como sacarle partido a Azure desde nuestras aplicaciones Xamarin. Por Marcos Cobeña.

• 12:00 – 2:00PM Hands on Lab. ¿Crear una aplicación Xamarin paso a paso con MVVM, uso de servicios web y accediendo a características de cada plataforma?. En este taller realizaremos una aplicación con esas características entre todos. Anímate y ven con tu portátil preparado!

• 2:00 – 3:00PM Comida.

• 3:00 – 4:00PM Hands on Lab.

El lugar

El evento se celebrará en el WorkINCompany. Dirección detallada:

Calle Rioja 13, 1º C, Sevilla

WorkINCompany
WorkINCompany

La fecha

El evento tendrá lugar el próximo Sábado, 10 de Septiembre de 9:00h a 16:00h. Tendremos tres sesiones técnicas de  40 minutos de duración cada una junto a un taller de 3 horas de duración. Además contaremos con regalos y sorpresas.

¿Te apuntas?

Más información

[Material XDev Madrid] WinObjc: De iOS a Windows y extendiendo Xamarin.Forms

El evento

El pasado 09 de Agosto, desde el grupo XDev en Madrid, se organizaba un evento veraniego centrado en desarrollo móvil multiplataforma, con temas como convertir aplicaciones de iOS a UWP o extender Xamarin.Forms, además de tener momentos para el networking y algun que otro detalle con los asistentes.

El material

Pude participar en el evento con dos sesiones.

En la primera de ellos, nos centramos en el Windows Bridge para iOS, WinObjC. Convertimos algunas aplicaciones iOS a UWP e incluso vimos como añadir características específicas de la plataforma Windows como el uso de Live Tiles.

En la segunda sesión, nos centramos en como extender Xamarin.Forms para poder acceder a características específicas de cada plataforma, crear nuevos controles o efectos con el objetivo de ofrecer la mejor experiencia posible en cada plataforma, aun compartiendo gran parte de la interfaz de usuario.

En cuanto a las demos técnicas realizadas, las tenéis disponible en GitHub:

Ver GitHub

Quisiera terminar añadiendo algunos agradecimientos. Gracias a todos los asistentes por asistir además de la constante participación con preguntas, en estas fechas y con tan poca antelación en el anuncio del evento es destacable; gracias a Dachi Gogotchuri por toda la ayuda en la organización y gracias a Liferay por sus increíbles instalaciones cediéndonos una sala. Nos vemos en la próxima!

Más información

[Evento XDev Madrid] WinObjc: De iOS a Windows y extendiendo Xamarin.Forms

600_449727003.jpegIntroducción

A finales del año pasado nació el grupo de usuario XDev en Madrid, grupo de desarrolladores multiplataforma de Madrid.

Aprovechando visita a la capital, ¿algo mejor que organizar un evento junto a un poco de coworking?

El evento

El evento tendrá lugar el próximo Martes, 09 de Agosto y contará con dos sesiones:

  • 19:00h – 20:00h – WinObjc: Cruzamos el puente desde iOS a Windows! ¿Tienes una aplicación iOS?, ¿quieres reaprovechar tus conocimientos y código Objective-C para acceder a la plataforma universal Windows?. En esta sesión conoceremos el Bridge de Windows para iOS, convertiremos algunas aplicaciones iOS a UWP e incluso veremos como añadir características específicas de la plataforma Windows como el uso de Live Tiles por ejemplo. ¿Te apuntas?
  • 20:00h – 21:00h – Profundizando y extendiendo Xamarin.Forms Xamarin.Forms es un framework que nos añade una capa de abstracción permitiendo desarrollar la interfaz de nuestras aplicaciones móviles multiplataforma una única vez, compartiendo el código de la UI. Veremos como crear aplicaciones con Xamarin.Forms además de centrarnos en cómo acceder a características propias de cada plataforma mediante la creación de servicios o Custom Renders.

Se realizará en Liferay en sus oficinas de Paseo de la Castellana, 280, 28046 Madrid.

¿Te apuntas?

Más información

[Xamarin.Forms] Utilizando DataPages

Forms-01-WFIntroducción a DataPages

En no pocas ocasiones nos planteamos realizar una aplicación sencilla para consultar información existente desde un servidor o infraestructura cloud.

En el marco del pasado Evolve 2016, Xamarin anunciaba la disponibilidad e la preview de Xamarin.Forms DataPages.

Los DataPages llegan para facilitar la creación de aplicaciones de tipo maestro-detalle con acceso a una fuente de información de la forma más rápida y sencilla posible. Se renderizarán listados y detalles automáticamente en base a los datos pudiendo personalizar con el uso de diferentes controles y el uso de temas.

DataPages se puede utilizar consumiendo el paquete NuGet Xamarin.Forms.Pages.

Permite acceder a diferentes fuentes de información con data sources prefabricados:

  • JsonDataSource: Una URL que contiene un JSON.
  • AzureDataSource (paquete NuGet separado): Azure Mobile Services.
  • AzureEasyTableDataSource (paquete NuGet separado).

Para mostrar la información correspondiente a la fuente de información contamos con una serie de páginas y controles.

Las páginas disponibles son:

  • ListDataPage: Muestra un listado de elementos.
  • DirectoryPage: Listado de elementos agrupados.
  • PersonDetailPage: Página de detalles que muestra la información correspondiente a un tipo de objeto.

En cuanto a controles:

  • ListItem: Vista prefabricada destinado a mostrar un elemento de un listado. Puede mostrar título, detalles e imagen.
ListItem
ListItem
  • CardView: Este control es similar al CardView nativo de Android. Permite mostrar un texto principal, uno secundario y una imagen.
CardView
CardView
  • HeroImage: Control que permite mostrar título, detalles e imagen, dándole peso a esta última. Tambien cuenta con una propiedad para modificar el aspecto.
HeroImage
HeroImage

Preparando la solución

Comenzamos creando una aplicación Xamarin.Forms utilizando una librería portable (PCL):

Nueva aplicación Xamarin.Forms
Añadir paquetes utilizando NuGet

Nueva aplicación Xamarin.Forms

Tras crear el proyecto debemos añadir la referencia a DataPages y Themes. Para ello, utilizaremos NuGet para añadir:

  • Xamarin.Forms.Pages
  • Xamarin.Forms.Theme.Base
  • Xamarin.Forms.Themes.Light o Xamarin.Forms.Themes.Dark
Añadir paquetes utilizando NuGet
Añadir paquetes utilizando NuGet

NOTA: Debemos añadir los paquetes NuGet tanto en la libería portable como en el proyecto específico de cada plataforma, tanto en iOS como en Android.

DataPages requiere el uso de temas para poder renderizar correctamente. Para ello, en App.xaml debemos añadir el namespace detema y añadirlo en los recursos de la aplicación.

Dependiendo del tema elegido, los espacios de nombre a utilizar son:

xmlns:light="clr-namespace:Xamarin.Forms.Themes;assembly=Xamarin.Forms.Theme.Light"    
xmlns:dark="clr-namespace:Xamarin.Forms.Themes;assembly=Xamarin.Forms.Theme.Dark"

Y para añadir el tema a utilizar dentro del conjunto de recursos de la aplicación:

<ResourceDictionary MergedWith="dark:DarkThemeResources" />        
<ResourceDictionary MergedWith="light:LightThemeResources" />

Por ahora, para completar el proceso de uso del tema, debemos añadir algo de código específico por cada plataforma para cargar las librerías correspondientes.

var x = typeof(Xamarin.Forms.Themes.DarkThemeResources);    
x = typeof(Xamarin.Forms.Themes.LightThemeResources);    
x = typeof(Xamarin.Forms.Themes.Android.UnderlineEffect);

En el caso de iOS código a ejecutar en el AppDelegate, en el de Android, en la actividad principal MainActivity.

Ejemplo básico

Añadimos la vista XAML principal de la aplicación. Incluimos el espacio de nombres correspondiente a DataPages para acceder y utilizar las páginas, controles y data sources incluidos.

xmlns:p="clr-namespace:Xamarin.Forms.Pages;assembly=Xamarin.Forms.Pages"

Añadimos:

<?xml version="1.0" encoding="UTF-8"?>
<p:ListDataPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:p="clr-namespace:Xamarin.Forms.Pages;assembly=Xamarin.Forms.Pages"
             x:Class="DataPagesDemo.SessionDataPage"
             Title="Sessions" StyleClass="Events">
    <p:ListDataPage.DataSource>
        <p:JsonDataSource Source="http://demo3143189.mockable.io/sessions" />
    </p:ListDataPage.DataSource>
</p:ListDataPage>

El resultado:

El resultado
El resultado

Increíble, ¿cierto?. Vamos a analizar el código  (escaso) añadido.

Hemos modificado el tipo de página de una ContentPage, página básica para añadir contenido en Xamarin.Forms por una ListDataPage. Xamarin.Forms DataPages nos ofrece este tipo de página que nos permite crear un maestro-detalle con suma facilidad en base una fuente de información.

Utilizando la propiedad DataSource de la página, creamos un JsonDataSource que se encargará de acceder a la información realizando la petición HTTP necesaria y parseando la información para permitir mostrarla en la UI realizando bindings.

¿Dónde realizamos el enlace de la UI con la información?. La propiedad StyleClass de la página permite acceder a un estilo. En este caso se utiliza «Events», estilo prefabricado que ya define lo necesario para enlazar correctamente con la fuente de información («title», «image», «presenter»).

Tenéis el código fuente del ejemplo básico disponible en GitHub:

Ver GitHub

Añadiendo personalización

Vamos a crear un segundo ejemplo donde personalizar aspectos como la fuente de información, el aspecto visual modificando controles utilizados y por supuesto, también los enlaces a la información.

Vamos a generar una fuente de información de pruebas utilizando Json generator. Reemplazamos la fuente utilizando el datasource de tipo JsonDataSource:

<p:ListDataPage.DataSource>
     <p:JsonDataSource Source="http://www.json-generator.com/api/json/get/clOPFoTImW?indent=2" />
</p:ListDataPage.DataSource>

A continuación, vamos a modificar la propiedad DefaultItemTemplate que permite especificar la apariencia de cada elemento dentro del listado. En lugar de utilizar el control CardView utilizado por defecto en el ejemplo anterior, vamos a utilizar un ListItem.

<p:ListDataPage.DefaultItemTemplate>
     <DataTemplate>
          <ViewCell>
               <p:ListItemControl
                    Title="{p:DataSourceBinding name}" 
                    Detail="{p:DataSourceBinding email}" 
                    ImageSource="{p:DataSourceBinding picture}"
                      DataSource="{Binding Value}">
               </p:ListItemControl>
          </ViewCell>
     </DataTemplate>
</p:ListDataPage.DefaultItemTemplate>

ListItem cuenta con propiedades Title, Detail e ImageSource para especificar sus valores, utilizando la palabra reservada DataSourceBinding enlazaremos con los campos deseados del archivo JSON.

Nuestra página quedaría finalmente:

<p:ListDataPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:p="clr-namespace:Xamarin.Forms.Pages;assembly=Xamarin.Forms.Pages"
             x:Class="DataPages.MainView"
                   StyleClass="Events" 
                   Title="Users">   
    <p:ListDataPage.DataSource>
        <p:JsonDataSource Source="http://www.json-generator.com/api/json/get/clOPFoTImW?indent=2" />
    </p:ListDataPage.DataSource>
    <p:ListDataPage.DefaultItemTemplate>
        <DataTemplate>
            <ViewCell>
            <p:ListItemControl
                Title="{p:DataSourceBinding name}" 
                Detail="{p:DataSourceBinding email}" 
                ImageSource="{p:DataSourceBinding picture}"
                  DataSource="{Binding Value}">
                </p:ListItemControl>
            </ViewCell>
        </DataTemplate>
    </p:ListDataPage.DefaultItemTemplate>
</p:ListDataPage>

Tras ejecutar:

Personalización
Personalización

Además de contar con el listado, tenemos también disponible la vista de detalles mostrando más información a partir de los diferentes datos del JSON.

Y hasta aquí el repaso a las posibilidades de Xamarin.Forms DataPages. Una forma bastante rápida y sencilla para crear aplicaciones sencillas o prototipos con posibilidades interesantes en personalización y extensión. Siempre repitiendo cuatro sencillos pasos:

  1. Instalar paquetes NuGet.
  2. Seleccionar tema.
  3. Añadir DataPage.
  4. Configurar data source y personalización.

Tenéis el código fuente disponible e GitHub:

Ver GitHub

Recordad que podéis dejar cualquier comentario, sugerencia o duda en los comentarios.

¿Y próximamente?

DataPages continuará evolucionando y madurando con varios objetivos en mente. Xamarin ya ha confirmado que:

  • En próximas versiones no necesitaremos añadir código específico de plataforma para realizar la carga de las librerías correspondientes a temas.
  • Se incluirá la posibilidad de CRUD (create-read-update-delete).

Más información

[VideoBlog] Un vistazo a XenForms

XenFormsIntroducción

Xamarin.Forms es un framework que añade una capa de abstracción sobre la parte de UI permitiendo crear aplicaciones multiplataforma nativas compartiendo tanto la lógica de negocio como la interfaz de usuario. En los últimos tiempos hemos ido recibiendo tanto por parte de Xamarin como por parte de la comunidad gran cantidad de mejoras para aumentar el rendimiento en el desarrollo como el editor visual, Xamarin.Forms Previewer o Gorilla Player.

XenForms

La comunidad sigue creciendo a un ritmo imparable ofreciendo cada vez más y mejores opciones. Hoy estamos ante XenForms, herramienta creada por Michael Davis destinada a editar interfaces en Xamarin.Forms. Permite crear interfaces partiendo desde cero añadiendo Layouts y Views.

Construyendo la UI desde cero
Construyendo la UI desde cero

Además de poder editar cada propiedad de cada elemento, o los eventos.

Modificación de propiedades
Modificación de propiedades

También podemos cargar un proyecto ya existente para previsualizar la interfaz, hacer cambios al vuelo con el editor visual editando propiedades, hacer cambios a nivel de XAML, etc.

Carga de proyectos existentes
Carga de proyectos existentes

Suena interesante, ¿cierto?. Si te lo parece, no te pierdas el siguiente recorrido por la herramienta en video.

También se puede trabajar con Apps utilizando MVVM realizando pruebas de enlaces a datos (interactuar con la aplicación a la par que se edita), uso de propiedades avanzadas y adjuntas, etc.

Una herramienta interesante y sin duda con mucho potencial, ¿y a ti, qué te parece?.

Más información

[Xamarin] Utilizando SQLite

Database-WFIntroducción

El trabajo con datos en dispositivos móviles se ha convertido ya en algo común y habitual en el desarrollo de aplicaciones. Existe una gran variedad de tipos de datos y formas de almacenamiento:

  • Archivos de texto. Texto plano o html cacheado en el espacio de almacenamiento aislado de la aplicación.
  • Imágenes. En el espacio de almacenamiento aislado de la aplicación o almacenadas en directorios conocidos del sistema.
  • Archivos serializados. Archivos XML o Json con objetos serializados.
  • Bases de datos. Cuando se requieren datos estructurados, obtener información más compleja con consultas avanzadas entre otro tipo de necesidades, la posibilidad de las bases de datos es la elección idónea.

Las ventajas de utilizar una base de datos son múltiples:

  • Almacenamiento estructurado con eficacia alta.
  • Posibilidad de utilizar consultas y aplicar filtros.
  • Posibilidad de reutilizar conocimientos de base de datos en la gestión de datos en nuestras aplicaciones móviles.

Introducción a SQLite

SQLite es un motor de base de datos Open Source utilizado en todas las plataformas móviles y adoptado tanto por Apple como Google como Microsoft. El uso de SQLite en aplicaciones móviles es una gran opción ya que:

  • La base de datos es pequeña y fácil de portar.
  • La base de datos se concentra en un pequeño archivo.
  • Implementa la mayor parte del estándar SQL92.

Preparando el entorno

Comenzamos creando una aplicación Xamarin.Forms utilizando una librería portable (PCL):

Nueva aplicación Xamarin.Forms
Nueva aplicación Xamarin.Forms

Tras crear la aplicación, añadimos las carpetas básicas para aplicar el patrón MVVM además del paquete NuGet de Unity para la gestión del contenedor de dependencias.

Estructura del proyecto
Estructura del proyecto

Con el proyecto y estructura base creada, vamos a añadir SQLite al proyecto. Realm esta disponible en NuGet. Vamos a añadir en cada proyecto de la solución la última versión disponible del paquete utilizando NuGet. El paquete a utilizar es SQLite.Net PCL, implementación Open Source compatible con librerías portables (PCL) con soporte a .NET y Mono.

SQLite.Net PCL
SQLite.Net PCL

Tras añadir la referencia vamos a crear una interfaz que defina como obtener la conexión con la base de datos y abstraer la funcionalidad específica de cada plataforma. Trabajando con SQLite, el único trabajo específico a implementar en cada plataforma es determinar la ruta a la base de datos y establecer la conexión.

public interface ISQLite
{
     SQLiteAsyncConnection GetConnection();
}

En Android, la implementación de ISQLite nos permite establecer la conexión con la base de datos.

[assembly: Dependency(typeof(SQLiteClient))]
namespace TodoSqlite.Droid.Services
{
    public class SQLiteClient : ISQLite
    {
        public SQLiteAsyncConnection GetConnection()
        {
            var sqliteFilename = "Todo.db3";
            var documentsPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);

            var path = Path.Combine(documentsPath, sqliteFilename);

            var platform = new SQLitePlatformAndroid();

            var connectionWithLock = new SQLiteConnectionWithLock(
                                         platform,
                                         new SQLiteConnectionString(path, true));

            var connection = new SQLiteAsyncConnection(() => connectionWithLock);

            return connection;
        }
    }

}

NOTA: Utilizamos el atributo assembly:Dependency para poder realizar la resolución de la implementación con DependencyService.

En iOS, la implementación de ISQLite nos permite establecer la conexión con la base de datos. El archivo de la base de datos lo situamos dentro de la carpeta Library dentro del espacio de almacenamiento de la aplicación.

[assembly: Dependency(typeof(SQLiteClient))]
namespace TodoSqlite.iOS.Services
{
    public class SQLiteClient : ISQLite
    {
        public SQLiteAsyncConnection GetConnection()
        {
            var sqliteFilename = "Todo.db3";
            var documentsPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
            var libraryPath = Path.Combine(documentsPath, "..", "Library");
            var path = Path.Combine(libraryPath, sqliteFilename);

            var platform = new SQLitePlatformIOS();

            var connectionWithLock = new SQLiteConnectionWithLock(
                                          platform,
                                          new SQLiteConnectionString(path, true));

            var connection = new SQLiteAsyncConnection(() => connectionWithLock);

            return connection;
        }
    }
}

Todo listo para comenzar!

La definición de modelos

En nuestra aplicación, trabajaremos con elementos del listado ToDo, una única entidad sencilla.

public class TodoItem
{
     [PrimaryKey, AutoIncrement]
     public int Id { get; set; }
     public string Name { get; set; }
     public string Notes { get; set; }
     public bool Done { get; set; }
}

La gestión de campos especiales o relacionados las gestionamos mediante el uso de etiquetas. En nuestro ejemplo establecemos el campo Id como clave primaria gracias a la etiqueta PrimaryKey y además que autoincremente con el uso de AutoIncrement.

La interfaz de usuario

En nuestra aplicación contaremos con dos vistas, un listado de tareas y una vista de detalles para crear, editar o eliminar una tarea específica.

Comenzamos definiendo la vista principal. Tendremos un listado de tareas:

<ListView 
    ItemsSource="{Binding Items}" 
    SelectedItem="{Binding SelectedItem, Mode=TwoWay}">
    <ListView.ItemTemplate>
      <DataTemplate>
        <ViewCell>
          <ViewCell.View>
            <StackLayout 
              Padding="20,0,20,0"                       
              Orientation="Horizontal"       
              HorizontalOptions="FillAndExpand">
              <Label Text="{Binding Name}"
                     VerticalTextAlignment="Center"
                     HorizontalOptions="StartAndExpand" />
              <Image Source="check.png"
                     HorizontalOptions="End"
                     IsVisible="{Binding Done}"/>
            </StackLayout>
          </ViewCell.View>
        </ViewCell>
      </DataTemplate>
     </ListView.ItemTemplate>
</ListView>

A parte de definir como se visualizará cada elemento de la lista definiendo el DataTemplate establecemos la fuente de información, propiedad ItemsSource enlazada a propiedad de la ViewModel que obtendrá los datos de la base de datos.

Además del listado, debemos añadir en nuestra interfaz una forma de poder insertar nuevas tareas. Para ello, una de las opciones más habituales e idóneas es utilizar una Toolbar.

<ContentPage.ToolbarItems>
    <ToolbarItem Name="Add" 
                 Command="{Binding AddCommand}"  >
      <ToolbarItem.Icon>
        <OnPlatform x:TypeArguments="FileImageSource"
                    Android="plus"
                    WinPhone="Assets/add.png" />
      </ToolbarItem.Icon>
    </ToolbarItem>
</ContentPage.ToolbarItems>

Añadimos un ToolbarItem que permitirá añadir elementos.

La clase Device es muy importante en Xamarin.Forms ya que nos permite acceder a una serie de propiedades y métodos con el objetivo de personalizar la aplicación según dispositivo y plataforma. Además de permitirnos detectar el tipo de dispositivo, podemos detectar la plataforma gracias a la enumeración Device.OS o personalizar elementos de la interfaz gracias al método Device.OnPlatform entre otras opciones. En nuestro ejemplo, personalizamos el icono de añadir en base a la plataforma.

Nuestra interfaz:

Vista principal
Vista principal

Enlazamos la View con la ViewModel estableciendo una instancia de la ViewModel a la propiedad BindingContext de la página.

BindingContext = App.Locator.TodoItemViewModel;

En la ViewModel contaremos con una propiedad pública para definir el listado de tareas, además de la tarea seleccionada (utilizada para la navegación):

private ObservableCollection<TodoItem> _items;
private TodoItem _selectedItem;

public ObservableCollection<TodoItem> Items
{
     get { return _items; }
     set
     {
          _items = value;
          RaisePropertyChanged();
     }
}

public TodoItem SelectedItem
{
    get { return _selectedItem; }
    set
    {
          _selectedItem = value;
    }
}

Añadimos elementos con un comando disponible en la ViewModel.

private ICommand _addCommand;

public ICommand AddCommand
{
     get { return _addCommand = _addCommand ?? new DelegateCommand(AddCommandExecute); }
}

private void AddCommandExecute()
{

}     

Al pulsar y lanzar el comando, navegaremos a la vista de detalles.

_navigationService.NavigateTo<TodoItemViewModel>(_selectedItem);

Si creamos un nuevo elemento pasaremos como parámetro una nueva entidad de TodoItem, en caso de seleccionar una existente, pasaremos el seleccionado disponible en la propiedad SelectedItem.

Definimos la interfaz de la vista de detalles:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="TodoRealm.Views.TodoItemView"
             Title="{Binding Name}">
  <StackLayout 
    VerticalOptions="StartAndExpand" 
    Padding="20">
    <Label 
      Text="Name" />
    <Entry 
      Text="{Binding Name}"/>
    <Label 
      Text="Notes" />
    <Entry 
      Text="{Binding Notes}"/>
    <Label 
      Text="Done" />
    <Switch 
      x:Name="DoneEntry" 
      IsToggled="{Binding Done, Mode=TwoWay}"/>
    <Button 
      Text="Save"
      Command="{Binding SaveCommand}"/>
    <Button 
      Text="Delete"
      Command="{Binding DeleteCommand}"/>
    <Button 
      Text="Cancel"
      Command="{Binding CancelCommand}"/>
  </StackLayout>
</ContentPage>

Añadimos cajas de texto para poder editar toda la información de una tarea además de botones para poder guardar, borrar o cancelar y navegar atrás.

El resultado:

Detalle
Detalle

Para enlazar la información de un elemento seleccionado, debemos capturar la información enviada en la navegación. Creamos una propiedad pública para enlazar con la UI de la tarea:

private TodoItem _item;

public TodoItem Item
{
     get { return _item; }
     set { _item = value; }
}

¿Cómo capturamos el elemento seleccionado en la navegación?. Utilizamos el método OnAppearing para capturar el parámetro NavigationContext.

public override void OnAppearing(object navigationContext)
{
     var todoItem = navigationContext as TodoItem;

     if (todoItem != null)
     {
          Item = todoItem;
     }

     base.OnAppearing(navigationContext);
}

En cuanto a cada botón, cada uno de ellos estará enlazado a un comando:

private ICommand _saveCommand;
private ICommand _deleteCommand;
private ICommand _cancelCommand;

public ICommand SaveCommand
{
     get { return _saveCommand = _saveCommand ?? new DelegateCommand(SaveCommandExecute); }
}

public ICommand DeleteCommand
{
     get { return _deleteCommand = _deleteCommand ?? new DelegateCommand(DeleteCommandExecute); }
}

public ICommand CancelCommand
{
     get { return _cancelCommand = _cancelCommand ?? new DelegateCommand(CancelCommandExecute); }
}

private void SaveCommandExecute()
{

}

private void DeleteCommandExecute()
{

}

private void CancelCommandExecute()
{

}

Trabajando con SQLite

Para trabajar con la base de datos utilizaremos DependencyService para obtener la implementación de ISQLite y obtener una conexión.

private SQLiteAsyncConnection _sqlCon;
_sqlCon = DependencyService.Get<ISQLite>().GetConnection();

Para almacenar nuestras tareas, comenzamos creando la tabla necesaria en la base de datos.

public async void CreateDatabaseAsync()
{
     using (await Mutex.LockAsync().ConfigureAwait(false))
     {
          await _sqlCon.CreateTableAsync<TodoItem>().ConfigureAwait(false);
     }
}

Utilizamos el método CreateTableAsync<>() para crear la tabla.

Continuamos con las operaciones básicas de CRUD. Para obtener la información almacenada en una tabla podemos acceder a la tabla y obtener el listado utilizando el método ToListAsync.

public async Task<IList<TodoItem>> GetAll()
{
     var items = new List<TodoItem>();
     using (await Mutex.LockAsync().ConfigureAwait(false))
     {
          items = await _sqlCon.Table<TodoItem>().ToListAsync().ConfigureAwait(false);
     }

     return items;
}

NOTA: Podemos realizar consultar SQL utilizando el método QueryAync.

A la hora de insertar, verificamos si estamos ante un registro existente o no, para realizar el registro de un nuevo elemento o actualizar uno existente con los métodos InsertAsync o UpdateAsync respectivamente.

public async Task Insert(TodoItem item)
{
     using (await Mutex.LockAsync().ConfigureAwait(false))
     {
          var existingTodoItem = await _sqlCon.Table<TodoItem>()
                        .Where(x => x.Id == item.Id)
                        .FirstOrDefaultAsync();

          if (existingTodoItem == null)
          {
               await _sqlCon.InsertAsync(item).ConfigureAwait(false);
          }
          else
          {
               item.Id = existingTodoItem.Id;
               await _sqlCon.UpdateAsync(item).ConfigureAwait(false);
          }
     }
}

Eliminar es una acción sencilla realizada con el método DeleteAsync.

public async Task Remove(TodoItem item)
{
     await _sqlCon.DeleteAsync(item);
}

Tenéis el código fuente disponible e GitHub:

Ver GitHub

Recordad que podéis dejar cualquier comentario, sugerencia o duda en los comentarios.

Más información

[Material SVQXDG] Xamarin University Spring Fling 2016

600_449053644.jpegEl evento

El pasado 24 de Mayo, desde el grupo SVQXDG, grupo de desarrolladores Xamarin de Sevilla, organizábamos el Xamarin University Spring Fling 16.

Xamarin University Sprint Fling 2016
Xamarin University Sprint Fling 2016

Evento celebrado a nivel global por las comunidades Xamarin a lo largo de todo el mundo. En SVQXDG la idea era reunir estudiantes de Xamarin University, repasar las últimas novedades presentadas en el Xamarin Evolve y compartir experiencias y networking entre todos como viene siendo habitual además de repartir algun que otro regalo gracias al equipo de Xamarin University.

El material

Hicimos un breve repaso de que es, funcionamiento y estado actual de Xamarin University. Para llegar al plato fuerte donde de la forma más práctica posible vimos las grandes novedades del Evolve:

  • Editor visual de Xamarin.Forms
  • Simulador remoto de iOS en Windows
  • Xamarin.Forms Themes y DataPages
  • Uso controles nativos en Xamarin.Forms
  • Etc

En cuanto a las demos técnicas realizadas, las tenéis disponible en GitHub:

Ver GitHub

Quisiera terminar añadiendo algunos agradecimientos a Josué Yeray y Marcos Cobeña por participar junto a un servidor en las sesiones y por supuesto, muchas gracias a todos los asistentes.

Más información

[VideoBlog] Un vistazo a Xamarin.Forms Previewer

Introducción

Xamarin.Forms es un framework que añade una capa de abstracción sobre la parte de UI permitiendo crear aplicaciones multiplataforma nativas compartiendo tanto la lógica de negocio como la interfaz de usuario. En el pasado Evolve 2016 se mostraron novedades de peso permitiendo aumentar el rendimiento en el desarrollo además de nuevas caracterísiticas.

Xamarin.Forms Previewer

Hasta ahora, cada vez que queríamos previsualizar un cambio de una vista en Xamarin.Forms requería una compilación y despliegue de la aplicación a un emulador o dispositivo físico. No es de extrañar que una de las opciones más solicitadas en el trabajo con Xamarin.Forms fuese un editor visual. Gracias a un editor visual podríamos ver cada cambio al vuelo, de forma inmediata sin necesidad de compilaciones ni despliegues incrementando considerablemente nuestra productividad. La espera ha llegado a su fin. Xamarin ha lanzado la Preview (disponible para Xamarin Studio) de Xamarin.Forms Previewer, editor visual para Xamarin.Forms.

Además de poder previsualizar cualquier cambio en nuestro marcado XAML directamente al vuelo, Xamarin.Forms Previewer es capaz de:

  • Podemos cambiar la previsualización en iOS y Android rápidamente además de tamaños y orientación.
  • Mostrar Custom Renders.
  • Mostrar datos de prueba en diseño.

Ante una novedad de tanto peso, no es de extrañar que en este nuevo VideoBlog nos lancemos de lleno a probar todas las opciones disponibles.

Tenéis el código fuente disponible e GitHub:

Ver GitHub

Recordad que podéis dejar cualquier comentario, sugerencia o duda en los comentarios.

Más información

[Xamarin.Forms] Adaptando aplicaciones para Tablets

Tablet HoldIntroducción

Corría el año 2010, finales de Enero, cuando Steve Jobs presentaba al mundo el iPad. El resto de la historia todos la conocemos. No era la primera tableta del mundo, ni la que más posibilidades brindaba pero si que fue sin duda un momento importante en el mercado. La sucesión de modelos por parte de los chicos de Cupertino, la explosión vivida en factores, formas y rangos de precios en tabletas Android y también la evolución de tabletas y crecimiento de éxito en tabletas Windows y equipos duales demuestran el crecimiento e importancia en el sector de las tabletas.

Como desarrolladores nos afecta de forma directa. Cuando desarrollamos aplicaciones móviles, es importante tener en cuenta no solo diversas plataformas, también factores de forma incluyendo tabletas. Al desarrollar una aplicación móvil multiplataforma con Xamarin.Forms además de compartir la lógica de negocio, compartimos la interfaz de usuario.

Teniendo en cuenta que las vistas son compartidas, ¿cómo adaptamos una aplicación Xamarin.Forms a tabletas?. En este artículo, vamos a repasar todos los detalles y aspectos a tener en cuenta para lograr ofrecer la mejor experiencia posible en cada formato.

Nuestra aplicación móvil

Para adaptar una aplicación Xamarin.Forms móvil a tabletas necesitamos…una aplicación. Vamos a partir de un proyecto con una aplicación móvil para todas las plataformas que muestra información relacionada con la Formula 1. Cuenta con posibilidad de ver pilotos con sus estadísticas, circuitos, escuderías, etc.

Interfaz en teléfonos
Interfaz en teléfonos

La aplicación utiliza servicios web para acceder a la información y muestra la misma de diversas formas, desde información numérica a formato más visual como gráficas.

Nuestro objetivo será adaptar la aplicación a tabletas adaptando la interfaz de usuario, la navegación y los recursos utilizados.

Añadiendo soporte a Tabletas

Antes de adaptar estilos, vistas, navegación o recursos, debemos asegurarnos que la aplicación nativa en cada plataforma soportan las tabletas.

iOS

En el caso de iOS, es decir, iPads, la plantilla automática de Xamarin.Forms incluye soporte. Podemos revisarlo verificando si la propiedad Info.plist > Devices tiene asignado el valor Universal.

Android

El ecosistema Android es bastante variado y complejo contando con una enorme diversidad de tamaños de pantalla. Desde Apps Xamarin.Forms tenemos soporte a toda la variedad.

Windows

Xamarin.Foms cuenta con soporte a aplicaciones Universal Windows Platform también conocido por las siglas en inglés UWP. Las aplicaciones Universales en Windows 10 permite acceder a una enorme variedad de familias de dispositivos, desde teléfonos a tabletas y PCs.

Detectando si estamos en teléfono o tableta

Para poder modificar el comportamiento de la aplicación dependiendo de si estamos en un teléfono o una tableta, necesitamos verificar si estamos en uno u otro. Podemos utilizar la clase Device para acceder a la enumeración Device.Idiom para verificar si estamos en teléfono o tableta:

if (Device.Idiom == TargetIdiom.Tablet)
{

}
else
{

}

La enumeración Device.Idiom cuenta con los siguientes posibles valores:

  • Phone: Indica que estamos en un teléfono. iPhone, iPod touch, Windows Phone y dispositivos Android por debajo de los 600 dips.
  • Tablet: Estamos ante iPad, dispositivos Windows 8.1 o dispositivos Android por encima de los 600 dips.
  • Desktop: Valor que obtenemos en aplicaciones UWP.
  • Unsupported: No soportado.

La clase Device es muy importante en Xamarin.Forms ya que nos permite acceder a una serie de propiedades y métodos con el objetivo de personalizar la aplicación según dispositivo y plataforma. Además de permitirnos detectar el tipo de dispositivo, podemos detectar la plataforma gracias a la enumeración Device.OS o personalizar elementos de la interfaz gracias al método Device.OnPlatform entre otras opciones.

De igual forma que la clase Device nos brinda sus opciones desde código C#, tenemos acceso a ellas desde código XAML:

<OnIdiom 
     x:TypeArguments=""                  
     Phone=""                  
     Tablet=""/> 

Utilizando OnIdiom en cualquier elemento que compone el árbol visual, podemos personalizar propiedades del mismo según si estamos ante teléfonos o tabletas.

Adaptando la UI

En nuestra aplicación, podemos adaptar las diferentes vistas añadiendo diferentes estilos, tamaños de fuente, márgenes y espaciado según estamos en teléfonos o tabletas de forma muy sencilla:

<Label              
     Text="{Binding Driver.CompleteName}"             
     TextColor="White"             
     XAlign="Center">              
     <Label.FontSize>                
          <OnIdiom x:TypeArguments="x:Double"                     
               Phone="24"                  
               Tablet="28"/>             
     </Label.FontSize>            
</Label>

En el ejemplo anterior, el texto que utilizamos para mostrar el nombre de un piloto contará con un tamaño de fuente diferente en teléfonos y tabletas, siendo de mayor tamaño en el caso de contar con mayor tamaño de pantalla.

Adaptando recursos

De igual forma, utilizando OnIdiom podemos personalizar los recursos utilizados por teléfonos y tabletas.

<ContentPage.BackgroundImage>
     <OnIdiom x:TypeArguments="x:String"                  
     Phone="Splash.jpg"                  
     Tablet="Splash@2x.jpg"/>  
</ContentPage.BackgroundImage>

Adaptando la navegación

Poder detectar si estamos ante teléfono o tableta y adaptar los elementos visuales en función de ello esta genial. Podremos continuar compartiendo no solo la lógica sino las vistas de la aplicación añadiendo de forma sencilla cambios por tipo de dispositivo. Sin embargo, la exigencia de los usuarios móviles con la madurez del mercado móvil actual, hace que no sea siempre suficiente. Los usuarios actuales estan ya acostumbrados a experiencias adaptadas y de calidad para cada uno de sus dispositivos. En el caso específico de nuestra aplicación, un listado de pilotos sin aprovechar gran parte del ancho de la pantalla navegando a una vista de detalles, no es la mejor experiencia posible en tabletas.

Ante estos casos, podemos crear vistas específicas personalizadas para tabletas. Para tabletas creamos una nueva vista de tipo maestro-detalle que nos permitirá mostrar el listado de pilotos con su información de detalle a la vez, algo mucho más adaptado y apropiado en tabletas.

public class DriverListTabletView : MasterDetailPage    
{        
     private object Parameter { get; set; }
        
     public DriverListTabletView(object parameter)      
     {
            Title = "Drivers";

            Parameter = parameter;
            Master = new DriverListView(null);

            Detail = new ContentPage
            {
                Content = new StackLayout
                {
                    VerticalOptions = LayoutOptions.Center,
                    HorizontalOptions = LayoutOptions.Center,
                    Children =
                    {
                        new Label
                        {
                            Text = "Select a Driver",
                            FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label))
                        }
                    }
                }
            };
                           
            ((DriverListView)Master).ItemSelected = (driver) =>
            {
                Detail = new DriverDetailView(driver);

                if (Device.OS != TargetPlatform.Windows)
                    IsPresented = false;

            };

            IsPresented = true;
        }
}

El contenido de Master será la vista del listado de pilotos, mientras que el contenido de Detail será la vista de detalles de un piloto. De esta forma, ofrecemos la mejor experiencia posible en cada tipo de dispositivo pero reutilizando de nuevo, como objetivo siempre firme al utilizar Xamarin.Forms, la mayor cantidad de código posible.

Para modificar el flujo de navegación hacia la vista detalles del piloto utilizando exactamente la misma vista, modificamos la ViewModel del listado de pilotos añadiendo una Action para propagar el evento de selección hacia la nueva vista específica para tabletas.

Utilizando Device.Idiom verificamos si estamos ante teléfono o tableta y modificamos el flujo de navegación en consecuencia:

if (Device.Idiom == TargetIdiom.Tablet || Device.Idiom == TargetIdiom.Desktop)
     Detail = new NavigationPage(new DriverListTabletView(null));
else
     Detail = new NavigationPage(new DriverListView(null));

El resultado:

App Xamarin.Forms adaptada a tabletas
App Xamarin.Forms adaptada a tabletas

Tenéis el código fuente disponible e GitHub:

Ver GitHub

Recordad que podéis dejar cualquier comentario, sugerencia o duda en los comentarios.

Más información