[Xamarin.Forms] StateTriggers

Introducción

En forma de Preview acaba de llegar en Xamarin.Forms mejoras en VisualStateManager con el soporte a StateTriggers.

StateTriggers

Los StateTriggers representan un conjunto de reglas que aplican VisualStates basados ciertas condiciones. Ahora, cada VisualState cuenta con una colección de StateTriggerBase que indican cuando el VisualState se debe aplicar. Si alguno de los triggers esta activo, el VisualState será aplicado.

NOTA: Si has desarrollado previamente para UWP, el concepto de StateTriggers te será familiar.

StateTriggers es una Preview por lo que para usarlo, recuerda usar la siguiente etiqueta experimental:

Xamarin.Forms.Forms.SetFlags("StateTriggers_Experimental");

AdaptiveTrigger

Este trigger es muy versátil. Permite definir reglas en XAML basadas en el tamaño de la pantalla. Veamos un ejemplo:

Cuenta con dos posibles valores:

  • MinWindowHeight
  • MinWindowWidth

Veamos un ejemplo sencillo:

<Grid>
     <VisualStateManager.VisualStateGroups>
          <VisualStateGroup>
               <VisualState x:Name="Narrow">
                    <VisualState.StateTriggers>
                         <AdaptiveTrigger MinWindowWidth="0" />
                    </VisualState.StateTriggers>
                   <VisualState.Setters>
                        <Setter Property="BackgroundColor" Value="Blue" />
                   </VisualState.Setters>
              </VisualState>
              <VisualState x:Name="Medium">
                   <VisualState.StateTriggers>
                        <AdaptiveTrigger MinWindowWidth="720" />
                   </VisualState.StateTriggers>
                   <VisualState.Setters>
                        <Setter Property="BackgroundColor" Value="Red" />
                   </VisualState.Setters>
               </VisualState>
               <VisualState x:Name="Large">
                    <VisualState.StateTriggers>
                         <AdaptiveTrigger MinWindowWidth="1000" />
                    </VisualState.StateTriggers>
                    <VisualState.Setters>
                         <Setter Property="BackgroundColor" Value="Green" />
                    </VisualState.Setters>
               </VisualState>
          </VisualStateGroup>
     </VisualStateManager.VisualStateGroups> 
</Grid>

El resultado:

AdaptiveTrigger

El color de fondo del Grid será azul. Si el ancho de la ventana es mayor que 720 pasará (automáticamente) a ser rojo. Por último, el color cambiará a verde si el ancho es mayor que 1000.

CompareStateTrigger

CompareStateTrigger activará el trigger si el valor de Property es igual a Value.

<Grid>
     <VisualStateManager.VisualStateGroups>
          <VisualStateGroup>
               <VisualState x:Name="Checked">
                    <VisualState.StateTriggers>
                         <CompareStateTrigger Property="{Binding IsChecked, Source={x:Reference CheckBox}}" Value="True" />
                    </VisualState.StateTriggers>
                    <VisualState.Setters>
                         <Setter Property="BackgroundColor" Value="Green" />
                    </VisualState.Setters>
               </VisualState>
               <VisualState x:Name="UnChecked">
                    <VisualState.StateTriggers>
                         <CompareStateTrigger Property="{Binding IsChecked, Source={x:Reference CheckBox}}" Value="False" />
                    </VisualState.StateTriggers>
                    <VisualState.Setters>
                         <Setter Property="BackgroundColor" Value="Red" />
                    </VisualState.Setters>
               </VisualState>
          </VisualStateGroup> 
     </VisualStateManager.VisualStateGroups> 
     <CheckBox
           x:Name="CheckBox"/>
</Grid>

Veamos el resultado:

CompareStateTrigger

Como podemos ver, estamos modificando el BackgroundColor del Grid en base a si el CheckBox esta marcado o no. Si el ChechBox esta marcado, el color de fondo es verde, en otro caso será rojo.

Se puede utilizar enlace a datos por lo que la comparación puede ser con una propiedad de la ViewModel, una propiedad de un elemento visual, etc. abriendo una enorme variedad de posibilidades de forma muy sencilla.

DeviceStateTrigger

Un StateTrigger sencillo que nos permite activar VisualStates en base al dispositivo donde se ejecuta la App:

<Grid>
     <VisualStateManager.VisualStateGroups>
          <VisualStateGroup>
               <VisualState
                    x:Name="Android">
                    <VisualState.StateTriggers>
                         <DeviceStateTrigger Device="Android" />
                    </VisualState.StateTriggers>
                    <VisualState.Setters>
                         <Setter Property="BackgroundColor" Value="Blue" />
                    </VisualState.Setters>
               </VisualState>
               <VisualState
                    x:Name="iOS">
                    <VisualState.StateTriggers>
                         <DeviceStateTrigger Device="iOS" />
                    </VisualState.StateTriggers>
                    <VisualState.Setters>
                         <Setter Property="BackgroundColor" Value="Red" />
                    </VisualState.Setters>
               </VisualState>
          </VisualStateGroup> 
     </VisualStateManager.VisualStateGroups> 
</Grid>

Si ejecutamos en Android:

DeviceStateTrigger en Android

Y si la App se ejecuta en iOS:

DeviceStateTrigger en iOS

Sencillo, ¿verdad?.

OrientationStateTrigger

Este StateTrigger cuenta con la propiedad Orientation que nos permite aplicar VisualStates en base a la orientación del dispositivo:

<Grid>
     <VisualStateManager.VisualStateGroups>
          <VisualStateGroup>
               <VisualState
                    x:Name="Landscape">
                    <VisualState.StateTriggers>
                         <OrientationStateTrigger Orientation="Landscape" />
                    </VisualState.StateTriggers>
                    <VisualState.Setters>
                         <Setter Property="BackgroundColor" Value="Blue" />
                    </VisualState.Setters>
               </VisualState>
               <VisualState
                    x:Name="Portrait">
                    <VisualState.StateTriggers>
                         <OrientationStateTrigger Orientation="Portrait" />
                    </VisualState.StateTriggers>
                    <VisualState.Setters>
                         <Setter Property="BackgroundColor" Value="Red" />
                    </VisualState.Setters>
                </VisualState>
           </VisualStateGroup>
      </VisualStateManager.VisualStateGroups> 
</Grid>

El resultado:

OrientationStateTrigger

Sin necesidad de suscribirse a eventos o lógica extra.

StateTriggers y Surface Duo/Neo (Dual Screen)

Xamarin.Forms le da soporte a Surface Duo y Surface Neo (dispositivos con dos pantallas) con el paquete Xamarin.Forms.DualScreen principalmente gracias a TwoPaneView.

Sin embargo, en la librería Xamarin.Forms.DualScreen también tenemos StateTriggers específicos a la hora de gestionar la UI al trabajar con dos pantallas.

El SpanModeStateTrigger cuenta con la propiedad SpanMode que nos permite ajustar la UI usando VisualStates en base a si estamos usando una única pantalla, etc.

<Grid>
     <VisualStateManager.VisualStateGroups>
          <VisualStateGroup>
               <VisualState x:Name="NotSpanned">
                    <VisualState.StateTriggers>
                         <dualScreen:SpanModeStateTrigger SpanMode="SinglePane"/>
                    </VisualState.StateTriggers>
                    <VisualState.Setters>
                         <Setter Property="BackgroundColor" Value="Red" />
                    </VisualState.Setters>
               </VisualState>
               <VisualState x:Name="Spanned">
                    <VisualState.StateTriggers>
                         <dualScreen:SpanModeStateTrigger SpanMode="Wide" />
                    </VisualState.StateTriggers>
                    <VisualState.Setters>
                         <Setter Property="BackgroundColor" Value="Green" />
                    </VisualState.Setters>
               </VisualState>
          </VisualStateGroup>
     </VisualStateManager.VisualStateGroups>
</Grid>

Usando una única pantalla:

Utilizando una pantalla

Al usar dos:

Utilizando las dos pantallas

Han llegado StateTriggers a Xamarin.Forms y pronto llegarán más opciones relacionadas. En algunos casos, hay StateTriggers que nos permiten hacer algo que ya podíamos de forma sencilla (por ejemplo, ajustes en la UI al cambiar la orientación) mientras que en otros casos, abre muchas posibilidades. ¿Qué te parece esta nueva funcionalidad?. Recuerda, puedes dejar cualquier feedback en los comentarios de la entrada.

Más información