Cómo adaptar una aplicación Windows 8.1 a diferentes tamaños y orientaciones de pantalla

jueves, 9 de octubre de 2014


En Windows 8 una página tenía de forma predefinida 4 estados, uno por cada tamaño establecido que podía tener la ventana de una aplicación, Snapped, Filled, FullScreenPortrait y FullScreenLandscape, y estos tamaños eran fijos que no se podían redimensionar por el usuario. Los desarrolladores estabamos acostumbrados a no preocuparnos por la gestión de las diferentes resoluciones en nuestras aplicaciones, simplemete nos limitabamos a crear en nuestras páginas VisualStates para cada uno de estos 4 estados predefinidos y adaptar los controles que necesitaramos. Esto sucedía porque al usar las plantillas de proyecto para aplicaciones de la tienda de Windows con c# y xaml, venía una clase ya creada que era LayoutAwarePage, servía como clase base de las páginas en el proyecto. Esta clase entre otras cosas se encargaba de enterarse cuando el estado de una página cambiaba y realizar la transición al VisualState correspondiente.

Esto ha cambiado con Windows 8.1 ahora ya no hay estados predefinidos para una página, hay un nuevo modelo de tamaño de ventana, vamos a repasar en este artículo como podemos adaptar una aplicación de Windows 8.1 a diferentes tamaños y orientaciones. Primero vamos a ver cómo trabajaba la clase LayoutAwarePage con los estados predefinidos en la versión anterior y como debemos realizar ahora esta gestión.

Gestión de cambio tamaño de pantalla en Windows 8

En Windows 8, como ya hemos comentado, con la plantilla del proyecto venía una clase base llamada LayoutAwarePage, la gestión de la resolucion de pantalla de esta clase se basaba en el valor de ApplicationView.Value, que podía tener los valores Snapped, Filled, FullScreenPortrait y FullScreenLandscape. Para cada uno de estos cuatro ViewState la página base llamaba al método GotoState del VisualStateManager pasando como parámetro el mismo nombre del ViewState actual, de este modo en las páginas debiamos tener VisualStates con el mismo nombre que los estados predefinidos.

 <VisualStateManager.VisualStateGroups>
  <VisualStateGroup x:Name="ApplicationViewStates">
    <VisualState x:Name="FullScreenLandscape">
      <!--aqui storyboard con cambios-->
    </VisualState>
    <VisualState x:Name="Filled">
      <!--aqui storyboard con cambios-->
    </VisualState>
    <VisualState x:Name="FullScreenPortrait">
      <!--aqui storyboard con cambios-->
    </VisualState>
    <VisualState x:Name="Snapped">
      <!--aqui storyboard con cambios-->
    </VisualState>
  </VisualStateGroup>
</VisualStateManager.VisualStateGroups>


Y dentro de cada VisualState debíamos incluir un storyboard con los cambios a realizar en esa resolución.

<VisualState x:Name="FullScreenPortrait">
    <Storyboard>
        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="backButton" Storyboard.TargetProperty="Style">
            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PortraitBackButtonStyle}"/>
        </ObjectAnimationUsingKeyFrames>
    </Storyboard>
</VisualState>

Gestión de cambio de tamaño de pantalla en Windows 8.1

Ahora en Windows 8.1 ya no se incluye la página base LayoutAwarePage en las plantillas de proyecto de aplicaciones para la tienda de Windows, ya no existen estados predefinidos y la propiedad value de ApplicationView ha sido deprecada.

Ahora el tamaño de la ventana es más fluido, el usuario puede pasar a modo partido por defecto se situará a la mitad del ancho de la pantalla. Por defecto el tamaño mínimo de una aplicación es 500px. El usuario puede redimensionar el ancho del espacio que ocupa la aplicación cuando esta en modo partido, por lo tanto las decisiones de diseño de la ventana las debemos tomar en función del tamaño de la ventana que ocupa la aplicación. El tamaño mínimo de la aplicación podemos editarlo en el manifiesto del proyecto para que sea 320px como en la versión anterior. Ahora tenemos que definir nuestros propios VisualStates para nuestra aplicación en base a nuestras necesidades, ya no hay nada predefinido.

Para enterarnos de cambios en la pantalla nos suscribiremos al evento SizeChanged y debemos llamar a ApplicationView.GetForCurrentView para obtener información actual de la página. Esta función nos devuelve un ApplicacionView y podemos usar propiedades como Orientation, IsFullScreen, AdjacentToLeftDisplayEdge, AdjacentToRightDisplayEdge para tomar decisiones, además deberemos averiguar el tamaño de la ventana.

Para saber el ancho de la pantalla tenemos dos formas.

Si nos suscribimos al evento SizeChanged de la ventana, podemos acceder al parámetro de tipo WindowSizeChangedEventArgs y acceder a e.Size.Width.

Tambíen podemos usar Window.Current.Bounds para averiguar el tamaño de la ventana.

¿Cómo lo hacemos?

Lo primero que tenemos que hacer es decidir las resoluciones y orientaciones que vamos a cubrir en nuestra aplicación, después podemos definir VisualStates para cada uno de los casos que hayamos decidido. Combinando las propiedades de ApplicationView junto con el tamaño de la pantalla podemos crear una lógica que se encargue realizar la transición entre los diferentes estados cuando el tamaño o la orientación de la pantalla cambia. Esta lógica es interesante encapsularla en una clase base para que podamos reutilizarla a lo largo de todas las páginas de una aplicación.

¿Y Podríamos compartir esta clase base entre proyectos?, bueno eso va a depender de las resoluciones que cubramos en nuestras aplicaciones, si tenemos aplicaciones que tienen diferentes necesidades, es posible que cubran diferentes resoluciones también y al final lo mejor es que tengan diferentes VisualStates.

Ejemplo

Vamos a ver un ejemplo de página base donde vamos a tener unos VisualStates muy parecidos a las que se cubrian en Windows 8, FullScreenLandscape, FullScreenPortrait, Snapped, Filled, añadiendo otro más Narrow para la resolución de 500px, pero siguiendo la nueva metodología de Windows 8.1 basada en el tamaño y en la orientación. Recordad que no tenéis porque tener estos mismos VisualState, ni los mismos nombres, ya que va a depender de las necesidades de tu aplicación. Podríamos denifir cualquier nombre para los VisualState por ejemplo como DefaultLayout, FullLayout o como queramos.

/// 
/// Página base que gestiona los cambios de tamaño y orientación de 
/// la pantalla invocando los siguientes VisualStates
/// FullScreenLandscape, FullScreenPortrait, Snapped, Narrow, Filled
/// 
public class PageBase : Page
{
    public PageBase()
    {
        this.Loaded += page_Loaded;
        this.Unloaded += page_Unloaded;
    }

    private void page_Loaded(object sender, RoutedEventArgs e)
    {
        Window.Current.SizeChanged += Window_SizeChanged;
    }

    private void page_Unloaded(object sender, RoutedEventArgs e)
    {
        Window.Current.SizeChanged -= Window_SizeChanged;
    }

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        UpdateVisualState();
    }

    private void Window_SizeChanged(object sender, WindowSizeChangedEventArgs e)
    {
        UpdateVisualState();

    }

    private void UpdateVisualState()
    {
        var visualState = string.Empty;
        var applicationView = ApplicationView.GetForCurrentView();

        if (applicationView.IsFullScreen)
        {
            if (applicationView.Orientation == ApplicationViewOrientation.Landscape)
                visualState = "FullScreenLandscape";
            else
                visualState = "FullScreenPortrait";
        }
        else
        {
            var size = Window.Current.Bounds;

            if (size.Width == 320)
                visualState = "Snapped";
            else if (size.Width <= 500)
                visualState = "Narrow";
            else
                visualState = "Filled";
        }

        VisualStateManager.GoToState(this, visualState, true);
    }
}


Fijaros que he llamado a la función UpdateVisualState cuando se lanza el evento SizeChanged de la ventana, este se lanzará cuando cambia la orientación, cuando llevas tu aplicación a una sección partida de la pantalla y cuando redimensionas esta sección partida de la pantalla. Pero también llamo a la función en el método OnNavigatedTo porque cuando pulsas el botón atras no salta el evento SizeChanged y si la resolución actual no es la misma que tenia la página anterior cuando estaba cargada, entonces no tendría el VisualState adecuado.

Resumen

En este artículo hemos visto como con la versión de Windows 8.1 ya no hay predefinidos estados visuales, sino que se debe controlar el cambio de tamaño de la pantalla donde se presenta la aplicación para adaptar los controles de la página que se esta visualizando.

Hemos visto una forma de poder gestionar los cambios en la pantalla en una aplicación y es teniendo una página base encargada de controlar la orientación y los cambios de tamaño de la pantalla. De esta forma podemos tener centralizado en un único sitio común a la aplicación la gestión a las diferentes resoluciones definidas en nuestra aplicación.

Libros relacionados

Windows 8.1 Apps with XAML and C# Unleashed

Pro Windows 8.1 Development with XAML and C#

No hay comentarios:

Publicar un comentario