Abril de 2018
Volumen 33, número 4
Fluent Design - Uso de Fluent: acción de gesto de pasar el dedo y animaciones conectadas
Por Lucas Haines | Abril de 2018
Los desarrolladores de aplicaciones deben abarcar cada vez más tipos de dispositivos, desde los populares smartphones, los tradicionales equipos de escritorio y los portátiles, hasta las pantallas táctiles de gran formato y las emergentes plataformas de realidad virtual y aumentada como HoloLens. El sistema Fluent Design se ha diseñado específicamente y evoluciona continuamente para facilitar a los desarrolladores la integración de características modernas para el ecosistema de dispositivos mixtos. Las características de Fluent que se han agregado a la plataforma Windows 10 en la actualización Fall Creators Update son un buen ejemplo, ya que permiten que las aplicaciones se perciban de manera natural, independientemente del dispositivo en que se ejecuten.
Las características de la UI de Fluent, como la luz, el desenfoque y la profundidad, se combinan para permitir una experiencia atractiva e intuitiva que permita a los usuarios hacer más cosas. Pero, hasta hace poco tiempo, los usuarios tenían que esforzarse para aprovechar al máximo sus dispositivos. Con el nuevo Windows 10 Fall Creators Update, Fluent agrega dos características que resuelven dos problemas actuales: acciones de gesto de pasar el dedo y animaciones conectadas.
Acciones de gesto de pasar el dedo
No es ningún secreto que las ventas de equipos con pantallas táctiles no paran de crecer. La pregunta para los desarrolladores es cómo se pueden habilitar modelos de interacción que funcionen tanto con pantallas táctiles como con teclados y mouse tradicionales a fin de ayudar a los usuarios a hacer más cosas.
La respuesta son los comandos orientados a objetos, que han estado disponibles durante años a través de un clic con el botón derecho o la acción de mantener pulsado un elemento. Estos métodos demostrados se entienden bien, pero, con un poco de trabajo, puede incorporar aceleradores que aprovechen las funcionalidades del ecosistema de dispositivos para mejorarlos.
Especifique acciones de gesto, que son fantásticos aceleradores que funcionan tanto para usuarios de pantallas táctiles como para usuarios de teclado. Las acciones de gesto son un acelerador útil para comandos contextuales que suelen estar ocultos en un menú de clic derecho o en una barra de comandos independiente. Otros ejemplos de acciones de gesto son los botones activables, el gesto de pasar el dedo y los aceleradores de teclado.
Pasar el dedo para activar comandos no es un concepto nuevo. El patrón de interacción existe tanto en Google Material Design como en Apple iOS. Resulta útil para evaluar rápidamente las prioridades de los elementos de una lista (por ejemplo, eliminar varias fotos o correos electrónicos de una lista) o para revelar los comandos más utilizados de un escenario. El control al pasar el dedo XAML permite agregar esta fantástica funcionalidad a sus aplicaciones para la Plataforma universal de Windows (UWP) fácilmente.
El control al pasar el dedo tiene dos comportamientos: modo Reveal y modo Execute:
El modo Reveal puede mostrar uno o más comandos asociados con un elemento seleccionado para que un usuario pueda seleccionar entre ellos. Por ejemplo, si tiene una lista de mensajes y quiere habilitar el reenvío rápidamente, crear un recordatorio de seguimiento o programar una reunión, el modo Reveal lo hace posible sin que el usuario tenga que navegar por pantallas. Esto puede resultar muy útil para los usuarios “móviles”.
El modo Execute completa el comando con un sencillo gesto. El ejemplo más común y sencillo sería la eliminación. Por ejemplo, ya no necesito este mensaje y quiero olvidarme de que existió. Un sencillo gesto (por ejemplo, pasar el dedo hacia la izquierda) y se envía a la papelera de reciclaje. El modo Execute no tiene que ser destructivo. Otro buen ejemplo es pasar el dedo para guardar. Por ejemplo, tiene una lista de clientes en una columna y, cuando selecciona uno, se muestra un panel de detalles a la derecha. Después de hacer cambios en el formulario o el registro del cliente, este, simplemente, pasa el dedo por encima para guardar los cambios. Fácil y rápido.
Sin embargo, para poder crear el comportamiento del gesto de pasar el dedo en la lista, me gustaría configurar SymbolIconSource para mi aplicación. Esto proporciona una forma muy sencilla de acceder a los iconos para la aplicación. Agregar símbolos a page.resources me permite agregar iconos fácilmente donde los necesito en otro momento en el código. Independientemente de la implementación del gesto de pasar el dedo, esto es genial para poder leer el código más fácilmente y poder aprovechar IntelliSense en Visual Studio. Este es el código:
<Page.Resources>
<SymbolIconSource x:Key="ReplyIcon" Symbol="MailReplyAll" />
<SymbolIconSource x:Key="PinIcon" Symbol="Pin" />
<SymbolIconSource x:Key="DeleteIcon" Symbol="Delete" />
</Page.Resources>
Con los recursos cargados, puedo empezar a implementar la API de gesto de pasar el dedo en un elemento. Las vistas de lista son un elemento extremadamente común para implementar gestos de pasar el dedo, así que trabajaré con eso, como se muestra en el código de la Figura 1.
Figura 1 Implementación del gesto de pasar el dedo en ListView
<ListView x:Name="MainList" Width="400" Height="500">
<ListView.ItemTemplate>
<DataTemplate x:DataType="x:String">
<SwipeControl x:Name="LVSwipeContainer"
LeftItems="{StaticResource RevealOptions}"
RightItems="{StaticResource ExecuteDelete}">
<StackPanel Orientation="Vertical" Margin="5">
<TextBlock Text="{x:Bind}" FontSize="18" />
<StackPanel Orientation="Horizontal">
<TextBlock Text="Data Template Font" FontSize="12" />
</StackPanel>
</StackPanel>
</SwipeControl>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Observe en la Figura 1 que estoy usando la propiedad LeftItems y RightItems de la API SwipeControl. LeftItems determina qué pasa cuando el usuario pasa el dedo hacia la izquierda (en este caso, RevealOptions) y coloca los botones de comando a la derecha.
El elemento de dirección hace referencia a un recurso estático, que se define en SwipeItems, en los recursos de página con el origen de mis iconos. En este punto, defino el modo de comportamiento como Reveal o Execute, como se muestra a continuación:
<Page.Resources>
<SwipeItems x:Key="RevealOptions" Mode="Reveal">
<SwipeItem Text="Reply" IconSource="{StaticResource ReplyIcon}"
Foreground="White"/>
<SwipeItem Text="Pin" IconSource="{StaticResource PinIcon}"
Foreground="White" />
</SwipeItems>
<SwipeItems x:Key="ExecuteOptions" Mode="Execute">
<SwipeItem Text="Delete" IconSource="{StaticResource DeleteIcon}"
Invoked="SwipeItem_Invoked"
Background="Red" Foreground="White" />
</SwipeItems>
</Page.Resources>
Ahora que he creado la UI y ya funciona la interacción, puedo usar la propiedad Invoke para configurar un controlador de eventos y procesar la acción. El procesamiento del comando al pasar el dedo se realiza en la declaración SwipeItems de page.resources al configurar la propiedad Invoked. Este es el código para hacerlo:
<SwipeItem Text="Delete" IconSource="{StaticResource DeleteIcon}"
Invoked="DeleteItem_Invoked"
Background="Red" Foreground="White" />
Una vez en el código subyacente, puede agregar su propio código para controlar el comando aquí:
private void DeleteItem_Invoked(SwipeItem sender,
SwipeItemInvokedEventArgs args)
{
int index = myListView.Items.IndexOf(args.SwipeControl.DataContext);
myListView.Items.RemoveAt(index);
}
Aunque el origen del gesto de pasar el dedo se encuentra en los dispositivos con pantalla táctil, también funciona muy bien con paneles táctiles y lápices. A menudo me doy cuenta de que, cuando trabajo con un dispositivo sin funcionalidad táctil, compruebo si puedo usar gestos de pasar el dedo en el panel táctil. Siempre me encanta descubrir que funciona. De forma predeterminada, las acciones de gestos de pasar el dedo de Fluent funcionan con los paneles táctiles, lo que ofrece a los usuarios más formas de completar sus tareas rápidamente y seguir avanzando. Es un ejemplo perfecto de implementación para un método de entrada que beneficia a todos los usuarios.
Cuando considere la posibilidad de agregar gestos de pasar el dedo a la aplicación, tenga en cuenta si estos gestos entrarán en conflicto con otros comportamientos de la aplicación. ¿Tiene FlipView, Hub o Pivot como área de contenido principal de la aplicación? Probablemente no sea el mejor sitio para implementar el gesto de pasar el dedo porque los patrones de interacción son muy parecidos y conseguir el equilibrio adecuado para los usuarios puede resultar difícil.
Pasar el dedo es genial cuando es necesario repetir la misma acción varias veces, pero recuerde que el resultado de la acción debe ser coherente. No puedo pensar en un escenario peor que el de un usuario que sepa que, al pasar el dedo hacia la izquierda, se guarda un elemento como favorito y que, en la pantalla siguiente, descubra que el mismo gesto lo elimina. Finalmente, una sugerencia: En mi experiencia, la opción de pasar el dedo para usuarios de funciones táctiles o mouse es mejor si el elemento sobre el que se hace tiene un ancho mínimo de 300 píxeles.
Animaciones conectadas
Hoy en día, muchas aplicaciones y sitios web tienen transiciones sin sentido. Cuando se lleva a cabo una acción que requiere la navegación de la página, solo se presenta al usuario la nueva página. Existen algunas pistas visuales (si las hay) que proporcionan contexto u orientación sobre qué hacer, dónde ir o cuáles son las novedades. Con las animaciones conectadas, puede conservar el contexto para el usuario y aumentar la participación. Por ejemplo, puede animar el elemento en el que se hace clic desde una lista a la ubicación de destino de la página de detalles. También puede mantener el avatar visible mientras el usuario navega por la aplicación. Se trata de mantener el contexto y el enfoque.
Agregar animaciones conectadas es un proceso incremental. Si quiere implementarlas para todas las transiciones de páginas, no quiero hacerle cambiar de idea. Pero tenemos mucho trabajo pendiente por hacer, de modo que puede que sea mejor ser selectivo y repartir el esfuerzo a lo largo del tiempo. Para implementar las animaciones conectadas, se necesitan dos pasos:
- Preparar un objeto de animación en la página de origen.
- Iniciar la animación en la página de destino.
Preparar la animación en la página de origen le permite definir el objeto de origen que se debe animar entre las páginas. Debe definir el mismo origen de imagen en la página de destino, aunque pueda usar una imagen con una resolución inferior. De este modo, reducirá el consumo de memoria de la aplicación. A continuación, la animación conectada se encadenará entre las dos imágenes.
La regla básica general de las animaciones conectadas es que la animación debe empezar unos 250 milisegundos entre los dos pasos. En caso contrario, el elemento de origen podría colgarse en la vista y acabar con un aspecto extraño. Con el motor de animación implícito que se incluye en Windows 10, si prepara una animación, pero no se inicia en tres segundos, el sistema la desecha.
Para este escenario, voy a usar ListView con cierto texto e imágenes con el código que se muestra en la Figura 2. Listview y Gridview tienen dos métodos agregados específicamente para las animaciones conectadas: PrepareConnectedAnimations y TryStartConnectedAnimationAsync.
Figura 2 Configurar la colección ListView para las animaciones
<ListView x:Name="Collection"
ItemClick="Collection_ItemClick"
ItemsSource="{Binding Source={StaticResource ItemsViewSource}}"
IsItemClickEnabled="True"
SelectionMode="None"
Loaded="Collection_Loaded"
Grid.Row="1">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:CustomDataObject">
<Grid Margin="0,12,0,12">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" MinWidth="150" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<!-- image to be animated-->
<Image x:Name="ConnectedElement" Source="{x:Bind ImageLocation}"
MaxHeight="100"
Stretch="Fill" />
<StackPanel Margin="12,0,0,0" Grid.Column="1" >
<TextBlock Text="{x:Bind Title}" HorizontalAlignment="Left"
Margin="0,0,0,6" />
<StackPanel Orientation="Horizontal" >
<TextBlock Text="{x:Bind Popularfor}" />
</StackPanel>
</StackPanel>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
El elemento clave de esta lista es el elemento x:Name de la imagen de DataTemplate. Este es el nombre que usaré al crear el elemento ConnectedAnimation y prepararlo para la página de destino. Cuando se hace clic en un elemento de la colección, se navega hasta la página nueva. Prepararé la animación conectada durante el método de clic. En el controlador de eventos definido en la lista Collection_ItemClicked prepararé ConnectedAnimation antes de la navegación. El método PrepareConnectedAnimation espera una clave única, el elemento, y el nombre del elemento que se animará. En el método, he asignado a la animación el nombre “ca1”, al cual haré referencia en la página de destino cuando se inicie la animación, como se muestra en la Figura 3.
Figura 3 Método PrepareConnectedAnimation
private void Collection_ItemClick(object sender,
ItemClickEventArgs e)
{
var container =
collection.ContainerFromItem(e.ClickedItem) as ListViewItem;
if (container != null)
{
_storeditem = container.Content as CustomDataObject;
var animation = collection.PrepareConnectedAnimation("ca1", _
storeditem, "ConnectedElement");
}
Frame.Navigate(typeof(DestinationPage), _storeditem);
}
SuppressNavigationTransitionInfo bloquea la reproducción de la animación de transición de página predeterminada y contribuye a evitar que interfiera con la animación conectada. Al usar el método OnNavigatedTo para la página de destino, creo ConnectedAnimation y paso la única clave que he creado en la página de origen (“ca1”). A continuación, llamo a TryStart y paso el nombre del elemento de imagen XAML que quiero animar mediante este código XAML:
<Image x:Name="detailedIamge" MaxHeight="400"
Source="{x:Bind ImageLocation}" />
Y este código C#:
ConnectedAnimation imageAnimation =
ConnectedAnimationService.GetForCurrentView().GetAnimation("ca1");
if (imageAnimation != null)
{
imageAnimation.TryStart(detailedIamge);
}
Esto crea la animación conectada unilateral de la vista de lista a la página de destino. Aún tengo que crear otra animación conectada para controlar el escenario de navegación inversa. Preparo la animación conectada en la invalidación OnNavigateFrom y le asigno una clave única, “ca2”, como se muestra en el código siguiente:
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
base.OnNavigatedFrom(e);
ConnectedAnimationService.GetForCurrentView().PrepareToAnimate("ca2", detailedIamge);
}
La animación ca2 se inicia mediante el método de colecciones cargadas declarado en la plantilla de vista de lista como se indica a continuación:
private async void Collection_Loaded(object sender, RoutedEventArgs e)
{
if (_storeditem != null)
{
ConnectedAnimation backAnimation =
ConnectedAnimationService.GetForCurrentView().GetAnimation("ca2");
if (backAnimation != null)
{
await collection.TryStartConnectedAnimationAsync(backAnimation, _
storeditem, "ConnectedElement");
}
}
}
Uso el método asincrónico TryStart invocado en la vista de lista para garantizar que el contenido de la vista de lista se rehidrate antes de que empiece la animación.
Normalmente, con listas o vistas densas de datos, tiene muchos datos secundarios asociados con el elemento: por ejemplo, el asunto del correo electrónico, el remitente, la fecha y hora, etc. Para ayudar aún más al usuario, podemos animar estos elementos en la vista. Esto requiere CoordinatedAnimation, que se puede hacer mediante la sobrecarga de dos parámetros para TryStart.
En primer lugar, necesito crear un elemento en la página de destino para mostrar el contenido adecuado. Uso un elemento StackPanel con un bloque de texto dentro y he asignado al elemento StackPanel el nombre CoordinatedPanel, como se muestra a continuación:
<StackPanel x:Name="CoordinatedPanel" Grid.Column="1"
VerticalAlignment="Top" Margin="20,0">
<TextBlock Text="{x:Bind HeaderText}" Style="{ThemeResource SubheaderTextBlockStyle}"
Margin="0,0,0,10" />
</StackPanel>
A continuación, uso la sobrecarga para TryStart para hacer referencia tanto a la animación conectada como al elemento de UI con el que se debe coordinar, como se muestra a continuación:
ConnectedAnimation imageAnimation =
ConnectedAnimationService.GetForCurrentView().GetAnimation("ca1");
if (imageAnimation != null)
{
imageAnimation.TryStart(detailedIamge, new UIElement[] { CoordinatedPanel });
}
Esto permite que tanto la animación conectada que he creado como cualquier otra animación de la UI se ejecute a la vez, lo que ayuda al usuario a comprender el contexto más rápidamente con una experiencia más inmersiva.
Una nota rápida: Evito usar animaciones conectadas si mi UI depende de solicitudes de red o cualquier operación asíncrona de larga ejecución entre la preparación y el inicio de la animación. Estos escenarios provocan un problema perceptible en la aplicación o provocan retrasos que desmerecen el impacto de la animación. Para compensar estas situaciones, considere la opción de cargar recursos e imágenes en la aplicación con anticipación.
Resumen
Las acciones de gesto de pasar el dedo y las animaciones conectadas son recursos útiles que pueden facilitar la interacción, agregar contexto visual y crear una experiencia atractiva e intuitiva para los usuarios finales. En el caso de las acciones de gesto de pasar el dedo, el patrón de interacción es fácil de implementar y agrega un nuevo nivel de eficiencia para el usuario que se amplía a los usuarios de paneles táctiles y lápices. Estas pequeñas interacciones pueden resultar útiles cuando los usuarios repiten las mismas acciones una y otra vez.
Las animaciones conectadas ayudan al usuario, ya que proporcionan contexto visual al navegar entre páginas y, al mismo tiempo, permiten una experiencia interactiva. Desde el punto de vista del desarrollador, las animaciones conectadas se pueden emplear de forma progresiva en momentos clave de la aplicación. El resultado: Los usuarios finales disfrutan de una experiencia más cohesionada y atractiva que los motiva para usar la aplicación más a menudo.
Lucas Haines trabaja con el equipo de controles XAML en Microsoft y su trabajo se centra en soluciones de UI y diseño para el sistema Fluent Design. También trabajó tres años en el estudio central de diseño de Windows, donde contribuyó a dar forma a la plataforma Fluent.
Gracias a los siguientes expertos técnicos de Microsoft por revisar este artículo: Steven Moyes, Kiki Saintonge
Kiki Saintonge es de Ellsworth, Maine, y le apasionan los videojuegos; en concreto, las tecnologías de UI y herramientas, lo que la llevó al estado de Washington a estudiar informática. Ha crecido con Windows y ahora trabaja en el desarrollo de los mejores controles y experiencias para el equipo de XAML de Microsoft.
Steven Moyes es administrador de programas de Microsoft en Redmond, Washington, y trabaja para que la creación de animaciones en XAML para UWP sea más fácil y eficaz. Dedica su tiempo libre a jugar a videojuegos, leer o trabajar en proyectos de programación personales.