[Xamarin.Forms Challenge] My Tasks

Introducción

Según evoluciona de Xamarin.Forms, llegan más y más opciones que simplifican la creación de diferentes elementos de la interfaz de usuario.

En el estado actual de Xamarin.Forms se pueden conseguir aplicaciones nativas de gran escala, con interfaces cuidadas y con alta integración con la plataforma. Hay que tener en cuenta el conjunto de Custom Renderers (código específico en cada plataforma) necesario para lograrlo.

NOTA:La elección entre Xamarin Classic o Xamarin.Forms es importante. Es necesario evaluar la aplicación a desarrollar, el conjunto de características específicas de cada plataforma (que pueden requerir un Custom Renderer), etc. 

En este artículo, vamos a tomar como referencia un diseño de Dribbble (por Anton Aheichanka), que intentaremos replicar con Xamarin.Formspaso a paso.

El diseño

My Tasks

Vamos a intentar replicar la UI del diseño paso a paso en Xamarin.Forms.

Los retos del ejemplo

Vamos a comenzar haciendo un análisis de la interfaz de usuario desglosando los elementos que la componen:

  • Cabecera: La cabecera cuenta con información del perfil de usuario. La imagen del perfil es circular algo que es sencillo de conseguir de diversas formas (FFImageLoadingcon transformaciones, ImageCirclePlugino incluso con SkiaSharp). La otra característica destacada de la cabecera es la imagen de fondo ya que tiene un corte horizontal sencillo pero que hace destacar aun más la cabecera. Entre las opciones que tenemos, una de las más sencillas es utilizar SkiaSharp.
  • El listado: El listado cuenta con una cabecera sencilla pero elegante, fácil de conseguir con la propiedad Header del ListView; elementos que se pueden conseguir definiendo una celda personalizada. En la celda, en caso de reuniones se muestran los participantes. Ahora gracias a BindableLayout es algo sencillo.
  • El menu de filtro: La característica principal de la vista. Una de mis APIs favoritas en Xamarin.Forms es la de animaciones. Sencilla pero ofrece una libertas muy alta. En este caso, podemos replicarlo usando una ContentView con imágenes en el interior y el efecto de apertura y cierre del menu lo conseguimos a base de animaciones (de escala, opacidad, etc.).

Imagen con corte horizontal

¿Cómo conseguimos la imagen con corte horizontal?

SkiaSharpsuele ser una opción ideal para opciones de dibujado. En este caso, nos vendría genial directamente dibujar la imagen pero recortando una pequeña parte (triangulo) de la parte inferior. SkiaSharp permite cargar imágenes además de tener una enorme variedad de posibilidades al tratar la misma. aplicar diferentes transformaciones, efectos, etc. Podemos hacer un recorte con trazado (un path) de una imagen.

Tras añadir los paquetes de SkiaSharp.Views.Formsa la solución, creamos un nuevo control que herede de SKCanvasView.

Comenzamos definiendo el trazado que usaremos para recortar la imagen:

SKPath Path = SKPath.ParseSvgPathData("m 0 0 l 400 0 l 0 300 l -400 -50");

Usamos el método ClipPathpara hacer el recorte:

canvas.ClipPath(Path);

Para dibujar la imagen usamos SKBitmap que pintaremos con el método DrawBitmap:

canvas.DrawBitmap(_bitmap, info.Rect);

Sencillo, ¿verdad?

Listado

Llegamos al listado. No tiene nada especialmente complejo, pero vamos a ir desglosando cada bloque. Comenzamos por la cabecera. Nos apoyamos en la propiedad Header del ListView para definir la misma:

<ListView.Header>
     <templates:TaskHeaderTemplate />
</ListView.Header>

Donde TaskHeaderTemplatees un ContentViewcon la definición de la cabecera.

Cada elemento del listado es definido en el ItemTemplatedel listado:

<ListView.ItemTemplate>
     <DataTemplate>
          <ViewCell>
               <templates:TaskItemTemplate />
          </ViewCell>
     </DataTemplate>
</ListView.ItemTemplate>

En la definición de cada elemento del listado tenemos una peculiaridad. En caso de reunión, mostramos las personas que asisten. Para ello, hacemos uso de BindableLayoutintroducido en Xamarin.Forms 3.5:

<StackLayout
     Orientation="Horizontal"
     BindableLayout.ItemsSource="{Binding People}">
     <BindableLayout.ItemTemplate>
          <DataTemplate>
               <Grid>
                    <imageCircle:CircleImage 
                    Source="{Binding Photo}"
                    Aspect="AspectFit"
                    Style="{StaticResource PhotoStyle}"/>
               </Grid>
          </DataTemplate>
     </BindableLayout.ItemTemplate>
</StackLayout>

Pero nos sigue quedando una peculiaridad del ejemplo en el listado…

Animando cada elemento del listado

Cada vez que se añaden o quitan elementos al listado, se introducen con una breve pero efectiva animación de Fade In y translación hacia arriba.

¿Cómo lo conseguimos?

Vamos a crear una ViewCellpersonalizada. Para ellos creamos una clase que here de ViewCell y al añadir un elemento hijo:

protected override void OnChildAdded(Element child)
{
     base.OnChildAdded(child);

     uint duration = 750;

     var animation = new Animation();

     animation.WithConcurrent((f) => TaskItemTemplate.Opacity = f, 0, 1, Easing.CubicOut);

     animation.WithConcurrent(
     (f) => TaskItemTemplate.TranslationY = f,
     TaskItemTemplate.TranslationY + 50, 0,
     Easing.CubicOut, 0, 1);

     TaskItemTemplate.Animate("FadeIn", animation, 16, Convert.ToUInt32(duration));
}

La definición del ItemTemplate del ListView debe cambiar a algo como:

<ListView.ItemTemplate>
     <DataTemplate>
          <cells:TaskItemViewCell />
     </DataTemplate>
</ListView.ItemTemplate>

Voila!

Filtro circular

Y llegamos a la parte más atractiva del ejemplo.

¿Cómo conseguirla de forma sencilla?

Vamos a crear un ContentViewque contendrá primero la imagen del menu cerrado. Por otro lado, la imagen para cerrar el menu y el fondo expandido además de claro, una imagen por cada elemento del menu.

Haremos uso de GestureRecognizerspara capturar las pulsaciones en el menu o cada elemento del menú. Al pulsar haremos dos acciones.

Por un lado, lanzaremos un comando definido en el control:

public static readonly BindableProperty SelectedCommandProperty =
     BindableProperty.Create("SelectedCommand", typeof(ICommand), typeof(FilterMenu), null);

public ICommand SelectedCommand
{
     get { return (ICommand)GetValue(SelectedCommandProperty); }
     set { SetValue(SelectedCommandProperty, value); }
}

Y por otro lado, haremos uso de animaciones!. Veamos por ejemplo, que hacemos para abrir el menu:

await InnerButtonMenu.RotateTo(360, _animationDelay);
await InnerButtonMenu.FadeTo(0, _animationDelay);
await InnerButtonClose.RotateTo(360, _animationDelay);
await InnerButtonClose.FadeTo(1, _animationDelay);
await OuterCircle.ScaleTo(3.5, 100, Easing.Linear);
await N.FadeTo(1, speed);
await NW.FadeTo(1, speed);
await SW.FadeTo(1, speed);
await S.FadeTo(1, speed);

Ocultamos con una rotación el botón (imagen) para abrir el menu. a continuación mostramos el botón de cerrar y escalamos (importante!) el area del menu. Por último, cambiamos la opacidad de cada elemento del menu.

Sencillo, pero realmente espectacular y efectivo.

Esta idea de menu esta basada en un gran ejemplo de Alan Beechque Ricardo Vasquezha elaborado más para tener un control.

El resultado conseguido:

El resultado

Puedes encontrar el ejemplo en GitHub:

Ver GitHub

Hasta aquí el desglose del ejemplo. Lo terminamos sin Custom Renderers o efectos, haciendo uso de Xamarin.Forms y sus APIs para tareas complejas como el menú de filtro o el listado y apoyándonos en SkiaSharp para algunas tareas.

Cualquier duda o comentario es bienvenido en los comentarios!

Más información

[Xamarin.Forms] Utilizando Bindable Layouts

Introducción

En Xamarin.Forms tenemos un tipo especial de View llamada Layout. Un Layout es un contenedor para otros elementos permitiendo ayudar a posicionar y gestionar el tamaño de los elementos que contiene. En Xamarin.Forms contamos con una gran variedad de Layouts:

Layouts en Xamarin.Forms

Los más utilizados son el StackLayout y el Grid, y suele ser habitual hacer una composición de varios así como utilizarlos para crear controles, etc. Por ejemplo, en ocasiones se utiliza la combinación de ScrollView y StackLayout junto con ContentViews para crear un pequeño listado de elementos horizontal.

Bindable Layout

Con la llegada de Xamarin.Forms 3.5 pre2 nos llega Bindable Layout. En toda clase derivada de Layout<T>, contamos ahora con las siguientes propiedades:

  • ItemsSource: De tipo IEnumerable, soporta el enlace de una colección de datos.
  • ItemTemplate: De tipo DataTemplate, permitirá definir la apariencia visual de cada elemento.
  • ItemTemplateSelector: De tipo ItemTemplateSelector, permite poder elegir entre diferentes templates para cada elemento en base a ciertas condiciones.

Las propiedades resultan familiares conociendo otros controles en Xamarin.Forms como el ListView.

¿Recuerdas el ejemplo que hemos mencionado de listado horizontal?. Utilizando Bindable Layout todo se simplifica.

Uso básico

De la interfaz que estamos replicando, el caso más sencillo es el listado de amigos.

<StackLayout
     Orientation="Horizontal"
     BindableLayout.ItemsSource="{Binding Profile.Friends}">
     <BindableLayout.ItemTemplate>
          <DataTemplate>
          <Grid>
               <Grid.RowDefinitions>
                    <RowDefinition Height="*" />
                    <RowDefinition Height="Auto" />
               </Grid.RowDefinitions>
                    <imageCircle:CircleImage 
                         Grid.Row="0"
                         Source="{Binding Picture}"
                         Aspect="AspectFit"
                         Style="{StaticResource FriendImageStyle}"/>
                    <Label 
                    Grid.Row="1"
                         Text="{Binding Name}"
                         Style="{StaticResource FriendNameStyle}"/>
               </Grid>
          </DataTemplate>
     </BindableLayout.ItemTemplate>
</StackLayout>

El resultado:

Bindable StackLayout

Sencillo, ¿verdad?.

Utilizando Bindable Layout con DataTemplateSelector

Pasamos a una necesidad más compleja, la galería. En la galería vamos a necesitar mostrar elementos con diferente tamaño.

¿Qué podemos hacer?

Vamos a analizar que necesitamos:

  • Los elementos hacen wrapping.
  • Los elementos se organizan de izquierda a derecha.
  • Hay imágenes de diferente tamaño.

FlexLayout nos permitirá ambas opciones. Definimos el control:

<FlexLayout
     Style="{StaticResource GalleryStyle}" />

Utilizamos un estilo para habilitar el Wrapping, etc. A continuación, vamos a hacer uso de Bindable Layout para evitar definir N imágenes dentro del Layout.

<FlexLayout
     BindableLayout.ItemsSource="{Binding Profile.Gallery}"
     BindableLayout.ItemTemplateSelector="{StaticResource GalleryItemTemplateSelector}"
     Style="{StaticResource GalleryStyle}" />

Al contar con la necesidad de tener imágenes de diferente tamaño en la galería, vamos a utilizar la propiedad ItemTemplateSelector para utilizar diferentes plantillas:

<styles:GalleryItemTemplateSelector x:Key="GalleryItemTemplateSelector">
     <styles:GalleryItemTemplateSelector.MediumGalleryItemTemplate>
          <DataTemplate>
               <Image 
                    Source="{Binding Picture}"
                    Aspect="AspectFill"
                    StyleClass="photo, medium"/>
          </DataTemplate>
     </styles:GalleryItemTemplateSelector.MediumGalleryItemTemplate>
     <styles:GalleryItemTemplateSelector.BigGalleryItemTemplate>
          <DataTemplate>
               <Image 
                    Source="{Binding Picture}"
                    Aspect="AspectFill"
                    StyleClass="photo, big"/>
          </DataTemplate>
     </styles:GalleryItemTemplateSelector.BigGalleryItemTemplate>
     <styles:GalleryItemTemplateSelector.GalleryItemTemplate>
          <DataTemplate>
               <Image 
                    Source="{Binding Picture}" 
                    Aspect="AspectFill"
                    StyleClass="photo"/>
          </DataTemplate>
     </styles:GalleryItemTemplateSelector.GalleryItemTemplate>
</styles:GalleryItemTemplateSelector>

El resultado:

Bindable FlexLayout

Veamos el resultado completo:

El resultado

Puedes encontrar el ejemplo en GitHub:

Ver GitHub

¿Qué te parece Layout Bindable?. Recuerda, puedes dejar cualquier duda o comentario en la entrada!

Más información

[Preview] Primer vistazo a Xamarin.Forms CollectionView

Introducción

Como parte de las novedades que llegan con Xamarin.Forms 4.0 se encuentra el nuevo control CollectionView.

Xamarin.Forms CollectionView

CollectionView llega con el objetivo de mejorar lo ofrecido por el control ListView hasta ahora:

  • Facilitar más opciones como listados horizontales o Grids.
  • Cubrir opciones muy solicitadas (vista para cuando no hay contenido, etc.).
  • Mejorar rendimiento.
  • Etc.

Primeros pasos

Para habilitar CollectionView es necesario utilizar un flag antes de inicializar Xamarin.Forms (recuerda, estamos ante una preview).

global::Xamarin.Forms.Forms.SetFlags("CollectionView_Experimental");

Layout básico

Podemos conseguir el mismo Layout de un ListView de forma sencilla. Como ventaja, con CollectionView no es necesario utilizar celdas, es decir, no usaremos ViewCell. Esto tiene un impacto en el rendimiento, sobretodo en Android, pero manteniendo la estructura y Layout del ListView.

<CollectionView 
     ItemsSource="{Binding Monkeys}">
     <CollectionView.ItemTemplate>
          <DataTemplate>
               <Grid 
                    HeightRequest="48">
                    <Label 
                         Text="{Binding Name}"
                         FontSize="18"
                         VerticalOptions="Center"/>
               </Grid>
          </DataTemplate>
     </CollectionView.ItemTemplate>
</CollectionView>

El resultado:

Layout básico

Fíjate que usamos un DataTemplate sin necesidad de ViewCell!.

Listas horizontales

Por defecto, el CollectionView utilizar un layout lineal. Esto quiere decir que se pueden hacer listas verticales pero…también horizontales!.

El control CollectionView cuenta con la propiedad ItemsLayout. Podemos establecer esta propiedad a una nueva instancia de GridItemsLayout que cuenta con una propiedad Orientation para definir la orientación.

<CollectionView.ItemsLayout>
     <GridItemsLayout
          Orientation="Horizontal" />
</CollectionView.ItemsLayout>

El resultado:

Listas horizontales

Carousel

Algo similar pero más complejo, un Carousel. Contar con un elemento scrollable pero navegando de elemento en elemento. Contamos con un control llamado CarouselView, un control nuevo basado en CollectionView, que podemos utilizar para conseguir el formato clásico de «carta» y paso de elemento a elemento:

<CarouselView 
     ItemsSource="{Binding Monkeys}">
     <CarouselView.ItemsLayout>
          <GridItemsLayout
               Orientation="Horizontal" 
               SnapPointsAlignment="Center" 
               SnapPointsType="Mandatory"/>
     </CarouselView.ItemsLayout>
</CarouselView>

El resultado:

Carousel

Una de las características más interesantes que tenemos disponible es la posibilidad de controlar el comportamiento y alineación de cada elemento al hacer el desplazamiento. Lo conseguimos con las propiedades SnapPointsType y SnapPointsAlignment.

Grid

Por defecto, CollectionView utiliza un layout lineal. Es decir, por defecto podemos hacer listas verticales u horizontales. Como ya vimos previamente, con la propiedad ItemsLayout podemos modificar el comportamiento del Layout.

<CollectionView.ItemsLayout>
     <GridItemsLayout
          Orientation="Vertical"
          Span="2"/>
</CollectionView.ItemsLayout>

Utilizando GridItemsLayout podemos controlar la orientación con la propiedad Orientation y con la propiedad Span el número de elementos por fila o columna.

Grid Layout

Vista cuando no hay contenido

¿Qué ocurre cuando ItemsSource no tiene elementos?. Probablemente, hasta ahora con el ListView has jugado con paneles y visibilidad para dar feedback al usuario ante esta situación. CollectionView viene a mejorar esto. Podemos utilizar la propiedad EmptyView para mostrar cualquier contenido en caso de tener elementos.

<CollectionView 
     ItemsSource="{Binding Monkeys}">
     <CollectionView.EmptyView>
          <Grid>
          <Label 
               Text="No items"
               HorizontalOptions="Center"
               VerticalOptions="Center"/>
          </Grid>
     </CollectionView.EmptyView>
</CollectionView>

El resultado:

Sin contenido

Sencillo, ¿verdad?.

Tienes el ejemplo disponible en GitHub:

Ver GitHub¿Qué te parece?, ¿qué te resulta más interesante?. Recuerda, puedes dejar comentarios en la entrada!.

Más información

[Preview] Primer vistazo a Xamarin.Forms Visual

Introducción

A la hora de desarrollar aplicaciones multiplataforma, buscamos llegar a diferentes plataformas cada una de ellas con sus propias guías de estilo, controles e idiosincrasia. Sin embargo, en ocasiones como desarrolladores móviles buscamos conseguir el mismo aspecto. Con Xamarin.Forms, a pesar de contar con una capa de abstracción en la capa de UI permitiendo definir la interfaz una única vez, creamos aplicaciones nativas. Es decir, utilizando Xamarin.Forms utilizamos los controles nativos de cada plataforma. Para conseguir un mismo aspecto necesitamos utilizar Custom Renderers o efectos en ocasiones.

Xamarin.Forms Visual

Con Xamarin.Forms 4.0-pre1 nos llega una nueva forma de indicar una forma de renderizar los controles nativos con Visual.

Cuando utilizamos Visual, se utiliza el renderizado personalizado en cada plataforma en lugar del renderizado predeterminado.

NOTA: Utilizando Visual seguimos utilizando controles 100% nativos.

Para establecer el uso de Visual, utilizaremos la propiedad Visual:

<ContentPage 
     Visual="Material">

</ContentPage>

La propiedad Visual esta disponible en la clase VisualElement. Cualquier elemento hijo de otro heredará el valor de la propiedad y modificará su forma de renderizar. Por este motivo, si establecemos Visual a nivel de ContentPage aseguramos que cualquier elemento de la página utilizará el nuevo sistema de renderizado.

NOTA: El valor de la propiedad Visual puede cambiar en tiempo de ejecución.

Nos llega esta funcionalidad en modo Preview con la apariencia basada en Material Design. Actualmente, en la versión 4.0-pre1 contamos con Material Design en Android e iOS para los siguientes controles:

  • Button
  • Entry
  • Frame
  • ProgressBar

Para utilizar Visual, por ahora (recuerda, estamos ante una Preview) es necesario añadir la siguiente línea:

Forms.SetFlags("Visual_Experimental");

Antes de llamar a Forms.Init. Además, en iOS, es necesario añadir el paquete NuGet Xamarin.iOS.MaterialComponents.

NOTA: Visual requiere API 29 para funcionar en Android.

Veamos un ejemplo:

<Grid
     BackgroundColor="DarkGray">
     <Frame 
          Style="{StaticResource SignInFrameStyle}">
          <StackLayout 
               Style="{StaticResource SignInPanelStyle}">
               <Label 
                    Text="Sign in"
                    Style="{StaticResource SignInTitleStyle}" />
               <Entry 
                    Placeholder="Username" />
               <Entry 
                    IsPassword="True"
                    Placeholder="Password" />
               <Button 
                    Text="Sign in" 
                    Style="{StaticResource SignInButtontyle}"/>
          </StackLayout>
     </Frame>
</Grid>

El resultado:

Visual

Tienes el ejemplo disponible en GitHub:

Ver GitHub

Más información

[Material] Monkey Conf 2018

El evento

En España tenemos una comunidad .NET activa y diversa. Gracias a ello tenemos eventos anuales de gran calidad relacionadas con Azure, SQL Server e incluso AI. Sin embargo, a pesar de contar con una enorme variedad de desarrolladores Xamarin realizando grandes cosas, nos faltaba un evento donde reunirnos todos. Para solventar este problema, nace Monkey Conf 2018.

Con una enorme facilidad, hablando con compañeros y amigos el evento empezó a tomar forma muy rápidamente. Muchos quisieron patrocinar el evento (gracias a ellos pudimos tener desayuno, almuerzo, camisetas o regalar licencias), otros querían participar con sesiones, e incluso algunos se ofrecieron para ayudar con la organización, etc.

Gracias a todos ellos, el pasado 01 de Diciembre, celebramos la Monkey Conf 2018. A continuación, una pequeña galería del evento:

Fue un día lleno de sesiones técnicas de calidad. Es increíble ver sesiones donde se dan consejos de distribución y venta de apps basadas en la experiencia real con consejos de arquitectura de código. Esto demuestra el nivel y madurez de la comunidad Xamarin. Desde la recepción hasta el final, donde no podía faltar «el preguntón» (gracias a MFractor, LiveXaml y Steema por facilitarnos licencias) el día fluyo de forma natural, sin ningun problema de ningún tipo. Muchas gracias a sponsors, asistentes y ponentes por ello!.

Sponsors, gracias!

Quiero destacar un momento, inesperado y emotivo. Entre los ponentes decidieron darme una sorpresa y me regalaron un teclado Corsair mecánico que ya estoy utilizando. Como se suele decir, chicos, no teníais porque, pero muy agradecido!.

Muchas gracias!

El material

Vamos al material. Participé en el evento con una sesión acerca de Xamarin.Forms Shell.

Aprendimos en que consiste, vimos como funciona Visual para conseguir la misma apariencia en Android e iOS y también conocimos CollectionView.

Por la tarde participé en un taller de desarrollo de aplicaciones Xamarin.

Realizamos una divertida aplicación con Xamarin.Forms y Custom Vision para determinar si una foto tomada desde la aplicación, es un HotDot o no (si, la idea viene de la serie Silicon Valley de HBO).

En cuanto al material (ejemplos, demos), se esta recopilando todo en un repositorio disponible en GitHub:

Ver GitHub

Más información

[Evento] Monkey Conf 2018

El evento

Llega el evento técnico Xamarin que estabas esperando, Monkey Conf!.

Monkey Conf 2018

Monkey Conf será un evento gratuito, en el que trataremos temas relacionados con desarrollo móvil, Xamarin, Xamarin.Forms, App Center, testing y más…

La fecha

Será el próximo Sábado, 01 de Diciembre de 09:30h a 18:30h (GMT+1). Tendremos dos tracks en paralelo con diferentes sesiones técnicas de 50 minutos de duración cada una. Además contaremos con regalos y sorpresas!.

¿Te apuntas?

NOTA: Las entradas del evento son gratuitas pero limitadas!

El lugar

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

Paseo de la Castellana, 280, 28046 Madrid, Madrid

Liferay

Call 4 Papers

¿Has desarrollado una aplicación con Xamarin?, ¿quieres hablar acerca de como usas App Center?, ¿revisar las próximas novedades de Xamarin.Forms?, ¿un taller?. El C4P del evento está abierto y estoy seguro que puedes hablar sobre algun tema que interese y ayude al resto!

Más información

[Xamarin.Forms] Utilizando TitleView

Introducción

Necesitar personalizar la barra superior de la aplicación añadiendo un logo, o un texto personalizado (utilizando una fuente específica, múltiples líneas, etc.) es bastante habitual. Hasta ahora, en Xamarin.Formsera algo posible pero…utilizando un Custom Renderer. Es un punto positivo de Xamarin.Forms, poder crear un Custom Renderer para acceder a características y elementos específicos de cada plataforma. Sin embargo, añade la necesidad de añadir más código (por plataforma) para conseguir un resultado.

Sin embargo, con la llegada de Xamarin.Forms 3.2 nos llega TitleView, una nueva opción para personalizar la barra superior sin necesidad de llegar a necesitar código específico por plataforma.

TitleView

TitleViewes parte de NavigationPage, donde se muestra el contenido del título de una ContentPage.

Cabecera personalizada

Comenzamos por un ejemplo sencillo. Vamos a personalizar la cabecera con un icono y título:

<NavigationPage.TitleView>
     <StackLayout
          Orientation="Horizontal"
          VerticalOptions="Center"
          Spacing="10">
          <Image
               Source="Icon.png"
               Aspect="AspectFit" />
          <Label
               Text="TitleView"
               FontSize="18"
               TextColor="White"
               VerticalTextAlignment="Center" />
     </StackLayout>
</NavigationPage.TitleView>

Podemos añadir el contenido deseado tal y como haríamos en el contenido de una página.

El resultado:

Cabecera personalizada!

Comandos

Podemos utilizar los eventos, comandos e incluso GestureRecognizersen los elementos de la cabecera:

<NavigationPage.TitleView>
     <StackLayout
          Orientation="Horizontal"
          VerticalOptions="Center"
          Spacing="10">
          <Image
               Source="Icon.png"
               Aspect="AspectFit">
               <Image.GestureRecognizers>
                    <TapGestureRecognizer
                         Tapped="OnHeaderIconTapped"/>
               </Image.GestureRecognizers>
          </Image>
          <Label
               Text="TitleView"
               FontSize="18"
               TextColor="White"
               VerticalTextAlignment="Center" />
     </StackLayout>
</NavigationPage.TitleView>

En este sencillo, ejemplo, mostramos un dialogo al pulsar sobre el logo de la cabecera:

Gestos

Barra de búsqueda

Pasemos a un ejemplo más complejo y típico. Vamos a añadir una barra de búsqueda:

<NavigationPage.TitleView>
     <Frame
          CornerRadius="{OnPlatform 12, UWP=1}"
          BackgroundColor="{OnPlatform Transparent, Android={StaticResource WhiteColor}}"
          HasShadow="False"
          IsClippedToBounds="True"
          Padding="0">
          <Frame.Content>
               <SearchBar
                    x:Name="SearchBar"
                    Placeholder="Search movie..."
                    HorizontalOptions="FillAndExpand"
                    SearchCommand="{Binding SearchCommand}"
                    SearchCommandParameter="{Binding Text, Source={x:Reference SearchBar}}">
                    <SearchBar.Behaviors>
                         <behaviors:SearchTextChangedBehavior />
                    </SearchBar.Behaviors>
               </SearchBar>
          </Frame.Content>
     </Frame>
</NavigationPage.TitleView>

Mostramos un listado de peliculas de modo que, cada vez que cambia el texto de la barra de búsqueda, se actualiza el contenido de la página con el listado de películas filtrado.

El resultado:

Búsqueda

Puedes encontrar el ejemplo en GitHub:

Ver GitHub

Limitaciones o problemas conocidos actuales

Entre el listado de limitaciones actuales encontramos:

  • SearchBar debe ser contenido en un panel con HorizontalOptions=LayoutOptions.Fill y VerticalOptions=LayoutOptions.Fill, o bien, utilizar WidthRequest y HeightRequest específicos para que todo se vea correctamente en iOS.
  • TitleView no es compatible con Android FormsApplicationActivity.
  • El contenido no puede ser más grande que el tamaño predeterminado de la barra de navegación en iOS/UWP. En caso de intentarlo, habrá recorte de forma automática.
  • Ya contábamos con las propiedades BackTitle, Title, TitleIcon y ahora con TitleView ocupando el mismo espacio en la barra de navegación, puede que haya conflictos y espacio limitado para admitir todas estas propiedades al mismo tiempo. Esto variará según la plataforma y el tamaño de la pantalla.

Más información

[Material] Analizando interfaces de usuario avanzadas con Xamarin.Forms

El evento

El pasado 26 de Septiembre, teníamos en SVQXDG un divertido evento donde abriendo debate e intercambiando ideas algunos de los ejemplos revisamos opciones disponibles para conseguir interfaces atractivas con Xamarin.Forms. Vimos opciones como efectos, Custom Renderers, SkiaSharp, VisualStateManager, etc.

El material

A continuación puedes encontrar la presentación utilizada en el evento:

En cuanto a ejemplos, revisamos muchos ejemplos revisando UI y opciones en cada uno de ellos.

My Trip Countdown

Sencillo contador atrás hacia el momento de una fecha (viaje).

My Trip Countdown

Las claves:

  • Uso de SkiaSharp para crear progreso circularcon degradado.
  • Gestión de imágenes con efectos (circular).
  • Botón con degradado.

Puedes encontrar el ejemplo en GitHub:

Ver GitHub

Pulse Music

Interfaz de un reproductor de música.

Pulse Music

Las claves:

  • Uso de SkiaSharp para crear progreso circular.
  • Animaciones infinitas.
  • Gestión de imágenes con efectos (circular).

Puedes encontrar el ejemplo en GitHub:

Ver GitHub

Walkthrough

Creación de un Walkthrough con diferentes pasos animados.

Walkthrough

Las claves:

  • Uso de Carousel.
  • Animaciones con Lottie.
  • API de animaciones de Xamarin.Forms.

Puedes encontrar el ejemplo en GitHub:

Ver GitHub

Netflix

Ejemplo donde se replica la interfaz básica de Netflix.

Vista principal en Android

La claves de este ejemplo:

  • Navegación personalizada (logo, transparencias, etc.).
  • Listados horizontales.
  • Parallax.

Puedes encontrar el ejemplo en GitHub:

Ver GitHub

Movies

El último ejemplo que revisamos. Aplicación utilizando la API de TheMovieDB.

Movies

La claves de este ejemplo:

  • Crear aplicaciones para Linux y WPF utilizando Xamarin.Forms.
  • Personalizar estilos para Linux y WPF.
  • Aplicar temas GTK.

Puedes encontrar el ejemplo en GitHub:

Ver GitHub

Más información

Primer vistazo a Xamarin.Forms gui.cs Backend

Introducción

Las aplicaciones de consola son geniales!. Probablemente, has realizado alguna aplicación de consola con alguna pequeña (o gran) herramienta.Tener una aplicación de consola tiene ventajas: liviana, multiplataforma, rápida, etc.

¿Y si pudiesemos realizar aplicaciones de consola con Xamarin.Forms?.

gui.cs

Estamos ante un Toolkit de UI para .NET, .NET Core y Mono que permite crear apliaciones de consola (si, con interfaz!) para Linux, macOS y Windows. Creado por Miguel de Icaza.

gui.cs

El Toolkit cuenta con una variedad de controles:

Añade soporte a colores, reescalado de pantalla, eventos, async, etc. A nivel de gestión de vistas es bastante similar a otros frameworks de UI como GTK# .

Conceptos básicos

gui.cs cuenta on Application.Run, que facilita un bucle principal donde:

  • Procesar eventos de teclado.
  • Gestiona el foco.
  • Redibuja áreas de la pantalla.
  • Timers.
  • Etc.

Cada elemento visual, hereda de la clase View. Toda View cuenta con propiedades X, Y, Height y Width para la gestión de tamaño y posición. Todo se pone más interesante al poder realizar composición de Views.

¿Y por qué Xamarin.Forms?

Buena pregunta. El framework ya permite grandes posibilidades, es sencillo de usar, así que, ¿por qué?.

EL origen

Why not?

Xamarin.Forms cada vez llega a más plataformas tras los backends de WPF y GTK, además de seguir aumentando en posibilidades. Ya había utilizada gui.cs para herramientas y pruebas, vi un tweet, nació un reto personal y voila. ¿Por qué no añadir la posibilidad de crear aplicaciones de consola con Xamarin.Forms?.

Backend gui.cs

Disponible en GitHub y en NuGet, nace el backend de Xamarin.Forms de gui.cs.

NOTA: Todos los ejemplos anteriores estan realizados con Xamarin.Forms.

Actualmente con soporte a:

  • ContentPage
  • Layouts
  • Label
  • Button
  • Editor
  • Entry
  • ListView
  • ProgressBar
  • Switch

Paulatinamente se añadirá soporte a otras características y controles.

¿Cómo lo uso?

Partimos de una aplicación de consola. Tras crear la aplicación, añadimos el paquete NuGet Terminal.Gui.Forms:

Terminal.Gui.Forms

Se encarga de añadir las referencias necesarias tanto a Terminal.Gui como a Xamarin.Forms.

Creamos un Application de Xamarin.Forms:

public class App : Xamarin.Forms.Application
{
     public App()
     {
          MainPage = new MainView();
     }
}

Se encargará de iniciar y establecer la página inicial. La página inicial, creada con XAML:

<StackLayout>
     <Grid 
          Padding="10, 10, 10, 10">
     <Grid.RowDefinitions>
          <RowDefinition Height="Auto" />
          <RowDefinition Height="Auto" />
     </Grid.RowDefinitions>
     <Grid.ColumnDefinitions>
          <ColumnDefinition Width="60" />
          <ColumnDefinition Width="*" />
          <ColumnDefinition Width="100" />
     </Grid.ColumnDefinitions>
     <Label 
          Text="Search by Zip Code" 
          Grid.Row="0" 
          Grid.Column="0" 
          Grid.ColumnSpan="3"
          TextColor="White"
          Margin="0, 6"/>
     <Label 
          Text="Zip Code:" 
          Grid.Row="1"
          Grid.Column="0"
          Style="{StaticResource LabelStyle}"
          TextColor="#C0C0C0" />
     <Entry
          Grid.Row="1"
          Grid.Column="1"
          Text="{Binding ZipCode, Mode=TwoWay}"
          Margin="5, 0" />
     <Button 
          Text="Get Weather" 
          Grid.Row="1" 
          Grid.Column="2"
          Command="{Binding WeatherCommand}"/>
     </Grid>
     <StackLayout
          Padding="10, 10, 10, 10">
          <Label 
               Text="Location" 
               Style="{StaticResource LabelStyle}" />
          <Label 
               Text="{Binding Weather.Title}"
               Style="{StaticResource FieldStyle}" />
          <Label 
               Text="Temperature"
               Style="{StaticResource LabelStyle}" />
          <Label 
               Text="{Binding Weather.Temperature}" 
               Style="{StaticResource FieldStyle}" />
          <Label
               Text="Wind Speed"
               Style="{StaticResource LabelStyle}" />
          <Label 
               Text="{Binding Weather.Wind}"
               Style="{StaticResource FieldStyle}" />
          <Label 
               Text="Humidity" 
               Style="{StaticResource LabelStyle}" />
          <Label
               Text="{Binding Weather.Humidity}"
               Style="{StaticResource FieldStyle}" />
          <Label 
               Text="Visibility" 
               Style="{StaticResource LabelStyle}" />
          <Label 
               Text="{Binding Weather.Visibility}"
               Style="{StaticResource FieldStyle}" />
          <Label 
               Text="Time of Sunrise" 
               Style="{StaticResource LabelStyle}" />
          <Label
               Text="{Binding Weather.Sunrise}"
               Style="{StaticResource FieldStyle}" />
          <Label
               Text="Time of Sunset" 
               Style="{StaticResource LabelStyle}" />
          <Label 
               Text="{Binding Weather.Sunset}"
               Style="{StaticResource FieldStyle}" />
     </StackLayout>
</StackLayout>

Hacemos uso de:

  • Diferentes Layouts
  • Diferentes controles
  • Enlace a datos
  • Estilos
  • Etc

La página cuenta con una ViewModel enlazada que se encarga de usar un servicio que accederá a información de OpenWeatherMap para informar de datos climatológicos dado un código postal.

Sólo nos falta, en la clase Program, inicializar Terminal.Gui, XamarinForms; cargar nuestra aplicación; y ejecutar la misma:

public class Program
{
     public static void Main()
     {
          Terminal.Gui.Application.Init();
          Forms.Init();
          var app = new App();
          var window = new FormsWindow("WeatherApp");
          window.LoadApplication(app);
          Terminal.Gui.Application.Run();
     }
}

Sencillo, ¿verdad?. Veamos el resultado:

WeatherApp

Puedes encontrar el ejemplo en GitHub:

Ver GitHub

Recuerda, es una Preview…

Estamos ante la primera Preview con un soporte limitado de guis.cs y de Xamarin.Forms. Sin embargo, hay algunas características aun no disponibles:

  • Frame
  • Menus
  • ScrollView
  • Etc

Más información

Channel 9: Retro Computing with .NET

[Xamarin.Forms] Nueva extensión de marcado para OnPlatform y OnIdiom

Introducción

Xamarin.Formsañ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

A pesar de definir la interfaz de usuario una única vez para todas las plataformas, tenemos la posibilidad de realizar personalizaciones y adaptaciones para ofrecer la mejor experiencia posible en cada una de las plataformas soportadas.

La clase Device

La clase Devicesin duda alguna es una de las claves a la hora de personalizar la interfaz de usuario por plataforma. Esta clase contiene diversas propiedades y métodos para personalizar la UI y la funcionalidad en base a la plataforma.

Hasta ahora…

Dentro de la clase Device, la propiedad OSpermitía identificar la plataforma en la que se ejecuta la aplicación. La extensión demarcado OnPlatformpermite personalizar la interfaz por plataforma. La extensión OnPlatform esta soportada por la clase OnPlatformExtension (se permite la abreviatura OnPlatform desde XAML) que define las siguientes propiedades:

  • Default: Representa el valor por defecto que aplica a todas las plataformas.
  • Android: Valor aplicado en Android.
  • GTK: Valor aplicado en plataformas GTK.
  • iOS: Valor aplicado en iOS.
  • macOS: Valor aplicado en macOS.
  • Tizen: Valor aplicado en plataformas Tizen.
  • UWP: Valor aplicado en Universal Windows Platform
  • WPF: Valor aplicado en la plataforma Windows Presentation Foundation.

Hasta ahora, el uso de OnPlatform era:

<BoxView>
     <BoxView.Color>
          <OnPlatform x:TypeArguments="Color">
               <On Platform="Android" Value="Green" />
               <On Platform="iOS" Value="Blue" />
               <On Platform="UWP" Value="Orange" />
          </OnPlatform>
     </BoxView.Color>
</BoxView>

La extensión de marcado OnIdiompermite realizar personalizaciones de la apariencia basadas en el tipo de dispositivo donde corre la App. Soportado por la clase OnIdiomExtension define las siguientes propiedades:

  • Default: Valor por defecto, aplicado a todos los dispositivos.
  • Phone: Valor aplicado a teléfonos.
  • Tablet: Valor aplicado a tabletas.
  • Desktop: Aplicado a plataformas de escritorio.
  • TV: Valor aplicado a plataformas TV.
  • Watch: En este caso, el valor se aplica a plataformas Watch.

Donde, el uso de OnIdiom hasta ahora era:

<BoxView>
     <BoxView.Color>
          <OnIdiom x:TypeArguments="Color">
               <OnIdiom.Phone>Green</OnIdiom.Phone>
               <OnIdiom.Tablet>Blue</OnIdiom.Tablet>
               <OnIdiom.Desktop>Orange</OnIdiom.Desktop>
          </OnIdiom>
     </BoxView.Color>
</BoxView>

Hasta ahora…

Llega nueva extensión de marcado con Xamarin.Forms 3.2

Con Xamarin.Forms 3.2 llega una nueva versión de extensión de marcadopara OnPlatform y OnIdiom.

Veamos su uso con OnPlatform:

<BoxView 
     Color="{OnPlatform Red, Android=Green, iOS=Blue, UWP=Orange}"/>

Y con OnIdiom:

<BoxView 
     Color="{OnIdiom Red, Phone=Green, Tablet=Blue, Desktop=Orange}" />

Como podemos ver, se simplifica la verbosidad para conseguir el mismo resultado.

Puedes encontrar ejemplo en GitHub:

Ver GitHubY a ti, ¿qué te parece la novedad?.

Más información