[Xamarin.Forms] Bottom TabbedPage para Android

Xamarin.Forms 3.1

Con la llegada de Xamarin.Forms 3.1 llegan una gran cantidad de mejoras y correcciones (es genial ver que muchas vienen de la comunidad). Entre el conjunto de novedades tenemos la posibilidad de crear TabbedPage en la parte inferior en Android.

En este artículo, vamos a ver como crear una Bottom TabbedPage.

Bottom TabbedPage

Podemos crear una TabbedPage con posición en la parte inferior de forma muy sencilla en Android utilizando platform specific:

On<Xamarin.Forms.PlatformConfiguration.Android>().SetToolbarPlacement(ToolbarPlacement.Bottom);

El resultado:

Bottom TabbedPage

Tienes un ejemplo disponible en GitHub:

Ver GitHub

Más información

[Xamarin.Forms] Utilizando LiteDB

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.

En este artículo, vamos a conocer LiteDB y como utilizarlo con una aplicación Xamarin.Forms.

Recuerda

El mismo ejemplo que vemos en este artículo lo hemos visto previamente con:

Introducción a LiteDB

LiteDB es una base de da motor de base de datos Open Source  distribuido en una pequeña librería escrita en C# y compatible con .NET y .NET Standard. Inspirada en MongoDB almacena documentos BSON (Binary JSON).

Al ser compatible con .NET Standard 2.0, podemos utilizarla con Xamarin.iOS, Xamarin.Android y UWP con aplicaciones Xamarin.Forms.

Preparando el entorno

Comenzamos creando una aplicación Xamarin.Forms utilizando una librería .NET Standard:

Xamarin.Forms con librería .NET Standard

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

Estructura del proyecto

Con el proyecto y estructura base creada, vamos a añadir LitrDB al proyecto. LiteDB 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 LiteDB, implementación Open Source compatible con librerías .NET Standard.

LiteDB

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 LiteDB, 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 IPathService
{
     string GetDatabasePath();
}

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

public class PathService : IPathService
{
     public string GetDatabasePath()
     {
          var path = Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal), AppSettings.DatabaseName);
          if (!File.Exists(path))
          {
               File.Create(path).Dispose();
          }
          return path;
     }
}

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

En iOS, la implementación de IPathService 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.

public class PathService : IPathService
{
     public string GetDatabasePath()
     {
          string docFolder = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
          string libFolder = Path.Combine(docFolder, "..", "Library", "Databases");
          if (!Directory.Exists(libFolder))
          {
               Directory.CreateDirectory(libFolder);
          }
          return Path.Combine(libFolder, AppSettings.DatabaseName);
     }
}

Y por último en UWP:

public class PathService : IPathService
{
     public string GetDatabasePath()
     {
          return Path.Combine(ApplicationData.Current.LocalFolder.Path, AppSettings.DatabaseName);
     }
}

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
{
     public int Id { get; set; }
     public string Name { get; set; }
     public string Notes { get; set; }
     public bool Done { get; set; }
}

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 HorizontalOptions="End"
                                   IsVisible="{Binding Done}">
                                   <Image.Source>
                                        <OnPlatform x:TypeArguments="ImageSource">
                                             <On Platform="Android, iOS"
                                                  Value="check" />
                                             <On Platform="UWP"
                                                  Value="Assets/check.png" />
                                        </OnPlatform>
                                   </Image.Source>
                              </Image>
                         </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">
                     <On Platform="Android, iOS"
                         Value="plus" />
                     <On Platform="UWP"
                         Value="Assets/plus.png" />
                </OnPlatform>
          </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.TodoListViewModel;

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;
          OnPropertyChanged();
     }
}
public TodoItem SelectedItem
{
     get { return _selectedItem; }
     set
     {
          _selectedItem = value;
          OnPropertyChanged();
     }
}

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

private ICommand _addCommand;

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

private void AddCommandExecute()
{
}

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

var todoItem = new TodoItem();
_navigationService.NavigateTo<TodoItemViewModel>(todoItem);

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:

<StackLayout VerticalOptions="StartAndExpand"
     Padding="20">
     <Label Text="Name" />
     <Entry Text="{Binding Item.Name}" />
     <Label Text="Notes" />
     <Entry Text="{Binding Item.Notes}" />
     <Label Text="Done" />
     <Switch x:Name="DoneEntry"
          IsToggled="{Binding Item.Done}" />
     <Button Text="Save"
          Command="{Binding SaveCommand}" />
     <Button Text="Delete"
          Command="{Binding DeleteCommand}" />
     <Button Text="Cancel"
          Command="{Binding CancelCommand}" />
</StackLayout>

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;
          OnPropertyChanged();
     }
}

¿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)
{
     if (navigationContext is TodoItem todoItem)
     {
          Item = todoItem;
     }

     base.OnAppearing(navigationContext);
}

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

Trabajando con LiteDB

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

var db = new LiteDatabase(DependencyService.Get<IPathService>().GetDatabasePath());

Para almacenar nuestras tareas, comenzamos creando la colección necesaria en la base de datos.

_collection = db.GetCollection<TodoItem>();

Si la colección no existe en la base de datos, es creada.

Cada elemento guardado en LiteDB cuenta con una propiedad Id utilizado para identificarlo de manera única. Debeemos indicarle a LiteDB qué propiedad de nuestro objeto actuará como identificador. Podemos hacerlo usando atributos o un mapeador. Aquí utilizaremos Mappers.

var mapper = BsonMapper.Global;

mapper.Entity<TodoItem>()
.Id(x => x.Id);

Para obtener el listado de elementos de una colección utilizaremos el método FindAll:

var all = _collection.FindAll();

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 Insert o Update respectivamente.

var existingTodoItem = _collection.FindById(item.Id);

if (existingTodoItem == null)
_collection.Insert(item);
else
_collection.Update(item);

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

_collection.Delete(i => i.Id.Equals(item.Id));

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

[Quedada Informal] CartujaDotNet & SVQXDG

Quedada múltiple

Desde CartujaDotNet, grupo de usuarios .NET de Sevilla y SVQXDG, grupo de desarrolladores Xamarin de Sevilla, vamos a realizar una quedada informal (la última del año!) para charlar abiertamente sobre tecnologías Microsoft, Xamarin, herramientas utilizadas, intercambiar impresiones, etc. Además, se analizarán las próximas charlas ya planteadas y los eventos confirmados entre otros temas de interés. Al ser quedada de dos grupos diferentes creemos que es una gran oportunidad para conocer, intercambiar e interactuar entre ambos permitiendo a miembros de cada uno conocer a los del otro y tratar otros aspectos.

No hace falta confirmar asistencia, y por supuesto será gratuito.

¿Te apuntas?

A continuación tienes disponible la fecha, hora y lugar:

  • Día: 05 de Julio (Jueves)
  • Horario:  19:00h
  • Lugar: En la Terraza del McDonald’s de Santa Justa

Más información

[Xamarin.Forms] Novedades utilizando Resource Dictionaries

Resource Dictionaries

En toda aplicación móvil la apariencia visual es vital. Cada vez es mayor el esfuerzo depositado a la hora de crear aplicaciones atractivas a la par que intuitivas y en muchos casos conseguir una imagen única que diferencia a la Aplicación del resto es prioritario. Por este motivo, debemos de contar con opciones sencillas de poder personalizar los distintos elementos que componen la interfaz.

Los estilos permitir definir múltiples propiedades visuales de elementos de la interfaz de forma reutilizable.

Los recursos XAML son objetos que podemos reutilizar más de una vez. Hablamos desde un sencillo color o tamaño de fuente, a el uso de estilos. Los diccionarios de recursos o ResourceDictionaries permiten definir una zona donde definir recursos.

Hasta ahora…

Podíamos definir diccionarios de recursos en archivos totalmente independientes. Hablamos de una clase derivada de ResourceDictionary, que consta de un par de archivos. Por un lado tenemos el archivo XAML donde se definen los recursos y por otro lado, la clase subyacente encarga de realizar InitializeComponent.

NOTA: Para crear un archivo de tipo ResourceDictionary, crea una ContentPage o ContentView y renombra la clase base de ContentPage o ContentView a ResourceDictionary.

Veamos un ejemplo.

<?xml version="1.0" encoding="utf-8" ?>
<ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms"
     xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
     x:Class="ResourceDictionaries.MyResourceDictionary">

     <Style x:Key="LabelStyle"
          TargetType="Label">
          <Setter Property="TextColor"
               Value="Red" />
          <Setter Property="FontSize"
               Value="24" />
</Style>

</ResourceDictionary>

NOTA: Fíjate que utilizamos x:Class para establecer la clase subyacente necesaria.

Para utilizar el diccionario de recursos, creamos una instancia:

<ContentPage.Resources>
     <local:MyResourceDictionary />
</ContentPage.Resources>

La forma anterior de añadir el diccionario de recursos a pesar de ser válida es muy limitada ya que sólo nos permite utilizar los recursos del diccionario instanciado. Podríamos necesitar utilizar mñas de un diccionario de recursos o añadir otros recursos.

Para solucionar este problema, tenemos disponible la posibilidad de utilizar diccionarios de recursos combinados.

<ContentPage.Resources>
     <ResourceDictionary>
          <ResourceDictionary.MergedDictionaries>
               <local:MyResourceDictionary />
          </ResourceDictionary.MergedDictionaries>
     </ResourceDictionary>
</ContentPage.Resources>

Podemos combinar varias instancias de diccionarios de recursos en uno existente. Se puede realizar directamente desde XAML utilizando la propiedad MergedDictionaries.

Con la llegada de Xamarin.Forms 3.0

La combinación de ResourceDictionary se simplifica con la llegada de Xamarin.Forms 3.0. Por un lado, ya no es necesario utlizar las etiquetas MergedDictionaries ya que en su lugar, podemos agregar directamente otro ResourceDictionary utilizando la propiedad Source.

Además, Xamarin.Forms 3.0 crea automáticamente una instancia de ResourceDictionary por lo que ya no es necesario añadir estas etiquetas.

<ContentPage.Resources>
     <ResourceDictionary Source="MyResourceDictionary.xaml" />
</ContentPage.Resources>

Esta nueva sintaxis no crea una instancia del diccionario de recursos. Gracias a este cambio, ya no es necesario mantener la clase subyacente o code behind del diccionario de recursos (MyResourceDictionary.xaml.cs) por lo que podemos borrarlo además del atributo x:Class de la ráiz del diccionario.

Más simple y sencillo!

Puedes encontrar un ejemplo en GitHub:

Ver GitHub

Más información

[Material] Taller Xamarin en OpenSouthCode 2018

El evento

El pasado 01 y 02 de Juniose celebró en Málaga OpenSouthCode 2018, un evento gratuito para promocionar y dar a conocer las tecnologías abiertas: software/hardware libre y opensource.

El Material

He tenido la oportunidad de participar este año con un divertido taller de desarrollo con Xamarin.

El objetivo fue realizar una aplicación multiplataforma conXamarin.Formspara Android, iOS, UWP, macOS y Linux utilizando una Custom Vision. Tras una breve introducción donde repasamos conceptos básicos, comenzamos a crear la aplicación. Vimos una introducción al concepto de enlace a datos, MVVM y su aplicación, acceso a APIs nativas de cada plataforma y acabamos realizando peticiones HTTP para obtener información.

La aplicación realizada fue HotDotOrNot en inspiración de la serie “Silicon Valley”.

HotDotOrNot

Para acabar el taller nos relajamos con un divertido concurso de preguntas, algunos pequeños regalos, preguntas y networking.

Puedes encontrar la App realizada paso a paso en GitHub:

Ver GitHub

Más información

[Material DotNet2018] Xamarin.Forms Everywhere

El evento

El pasado 29 de Mayo tenía lugar la DotNet2018. Un gran día repleto de sesiones técnicas cubriendo todo el espectro de tecnologías .NET, desde Xamarin, Azure, IoT, VR, etc.

Fue un día genial de grandes sesiones pero también de encontrarte con grandes amigos, desvirtualizar a nuevos amigos, networking, etc. Quisiera agradecer a todos los ponentes y asistentes por hacer posible el evento. Y por supuesto, mi enhorabuena a toda la organización por hacer que algo tan grande y complejo fluyese de forma tan natural y sencilla.

El material

He tenido en placer de poder participar en el evento con una sesión acerca de Xamarin.Formsy nuevas plataformas o posibilidades.

Comenzamos el evento revisando Xamarin.Forms en Linux:

Xamarin.Forms en Linux

Puedes encontrar el ejemplorealizado en GitHub:

Ver GitHub

Continuamos viendo estado y opciones de Xamarin.Forms en WPF:

Xamarin.Forms WPF

Puedes encontrar el ejemplorealizado en GitHub:

Ver GitHub

Y continuamos con nuevos backends de Xamarin.Forms, y en esta ocasión hablamos de Ooui de Frank Krueger.

Desde el navegador!

Repasamos estado, un poco de WebAssembly y continuamos. Puedes encontrar el ejemplorealizado en GitHub:

Ver GitHubContinuamos viendo los primeros pasos del backend de Windows Forms y dimos paso a nuevas posibilidades.

Hablamos de wearables y Tizen.CircularUI, donde repasamos opciones principales, etc.

Posteriormente llegço el turno de IoT. Tras una breve introducción a Xamarin.IoT vimos como ya contamos con plantillas de proyectos e integración entre Xamarin.Forms (backend GTK#) con Xamarin.IoT.

Monitor de temperatura realizado con Xamarin.IoT y Xamarin.Forms

Puedes encontrar el ejemplorealizado en GitHub:

Ver GitHub

Tras ver nuevas plataformas o dispositivos con IoT o Wearables, nos centramos en nuevas posibilidades en UI. Hicimos un repaso de:

  • VisualStateManager
  • FexLayout
  • SkiaSharp
  • Etc

En este punto, vimos como crear interfaces combinadas con elementos 3Dcon Wave Engineo como combinar ARCorecon Xamarin.Forms creando Custom Renderers.

ARCore

Puedes encontrar el ejemplorealizado en GitHub:

Ver GitHub

Completamos el evento utilizando Xamarin.Forms para crear la UI de addins para Visual Studioen Windows y macOS.

El ejemplo:

Ver GitHub

Hasta el año próximo!

Y ya tenemos evento confirmado para el próximo año!. Apunta la fecha, 23 de Mayo.

DotNet 2019!

Allí nos vemos!

Más información