Tirando o máximo dos pixels - adaptando as alterações do estado de exibição

No Windows 8, seus aplicativos são executados em diferentes tamanhos de tela e em vários estados de exibição. Um usuário pode ajustar seu aplicativo para o tamanho de um monitor desktop de 20 polegadas ou preencher toda a tela de um tablet widescreen de 10 polegadas. Em cada um dos casos, será interessante que o seu aplicativo aproveite ao máximo o espaço disponível. Nesta postagem, mostrarei como é possível rastrear o tamanho atual e o estado de exibição do seu aplicativo no código e também darei dicas de como escrever seu aplicativo no Windows 8 Consumer Preview para lidar com as mudanças de tamanho de tela e estado de exibição.

Na //build/, mostramos como desenvolver seu aplicativo para diferentes cenários. Consulte, por exemplo, o XAML talk ou o HTML talk. Recentemente, no blog Criando o Windows 8, compartilhamos algumas de nossas pesquisas e ideias de design sobre colocação em escalas de tela. Em geral, é possível usar marcações para adaptar a alteração de tamanho de tela sem ser necessário escrever um código explícito. Mas em certos momentos, você precisará rastrear em qual estado de exibição o seu aplicativo está - ou seja, se o seu aplicativo está no modo retrato, tela inteira, preenchido ou ajustado - e escrever um código que reaja de acordo. Por exemplo, se você estiver usando um HTML ListView para exibir itens, você deverá usar um GridLayout quando estiver no modo tela inteira, mas use o ListLayout quando estiver no modo ajustado, como mostra esta imagem. Para XAML, você deve alterar, de maneira semelhante, entre um controle de GridView e um controle de ListView. Para entender como fazer isso, vamos começar analisando como detectar alterações de estado de exibição e redimensionamento no código.

O estado de exibição completa de um aplicativo de previsão do tempo mostra 3 linhas de 3 blocos cada, dispostas em uma grade. A tela da exibição ajustada na direita mostra os mesmos blocos dispostos em uma única coluna de blocos

A tela do estado de exibição completa na esquerda mostra um layout da grade (HTML) ou o controle de GridView (XAML):
a tela do estado de exibição ajustada na direita mostra um layout de lista (HTML) ou o controle de ListView (XAML):

Os fundamentos do redimensionamento e das alterações do estado de exibição

A maneira mais simples de lidar com o redimensionamento de tela e alterações de estado de exibição é a mesma para os aplicativos do Windows 8 escritos em XAML e em HTML: basta anexar as funções de retorno de chamada aos eventos apropriados que a estrutura respectiva fornece e consulta qualquer informação adicional necessária.

Por exemplo, em JavaScript, é possível criar um manipulador para um evento básico de redimensionamento de janela, que é uma função simples de retorno de chamada, como mostra o código de exemplo a seguir. É possível usar esse evento para detectar quando uma área de exibição para um aplicativo foi redimensionada e localizar as novas dimensões da área do aplicativo.

JavaScript

 function handleResize(eventArgs) {
    var appWidth = eventArgs.view.outerWidth;
    var appHeight = eventArgs.view.outerHeight;
    ...
}

window.addEventListener("resize", handleResize);

Da mesma maneira, em XAML, é possível usar o evento SizeChanged na janela atual para configurar um manipulador de evento:

C#

 private void OnWindowSizeChanged(object sender, Windows.UI.Core.WindowSizeChangedEventArgs e)
{
    double AppWidth = e.Size.Width;
    double AppHeight = e.Size.Height;
}

Window.Current.SizeChanged += OnWindowSizeChanged;

Durante a programação do seu aplicativo do Windows 8, é possível também usar o WinRT para consultar diretamente o estado de exibição atual. O WinRT fornece um valor de enumeração que informa o estado de exibição atual de um aplicativo.

JavaScript

 var currentViewState = Windows.UI.ViewManagement.ApplicationView.value;

C#

 var CurrentViewState = Windows.UI.ViewManagement.ApplicationView.Value;

Os aplicativos do Windows 8 escritos em JavaScript também suportam a função msMatchMedia, que opera através de um objeto de janela DOM e que pode ser útil quando você tiver um cenário com múltiplas consultas de mídia, como, por exemplo, a combinação do modo paisagem em tela inteira e uma tela com largura de 1600 pixels:

JavaScript

 var isSnapped = window.msMatchMedia(“(-ms-view-state:fullscreen-landscape) and 
(min-width: 1600px”).matches;

JavaScript

 function handleSnappedMode(mql) {
if (mql.matches) {
        ...
        }
}
window.msMatchMedia(“(-ms-view-state:fullscreen-landscape) and (min-width: 
1600px”).addListener(handleSnappedMode);

Redimensionamento e estado de exibição no consumer preview

Agora que revisamos os fundamentos sobre como acessar o estado de exibição e as informações do tamanho de tela, vamos discutir como implantar essa funcionalidade para lidar com o redimensionamento de tela. No Windows 8 Consumer Preview, a ordem dos eventos de redimensionamento e dos eventos de alteração de estado de exibição é fundamental para que os eventos de estado de exibição (e as funções de retorno de chamada associadas) ocorram sempre antes de eventos de redimensionamento. Por essa razão, você deverá sempre esperar que um evento de redimensionamento seja disparado antes de acessar o estado de exibição atual. Isso oferece uma abordagem fácil e uniforme para lidar com as alterações de tamanho e estado de exibição no seu código. Ao esperar que os eventos de redimensionamento disparem (e esperar que todas as funções de retorno de chamadas associadas sejam executadas), é possível assegurar que as informações retornadas para a área de exibição e estado de exibição atuais estarão em sincronia.

Também recomendo que você use eventos de redimensionamento para disparar códigos que lidem com as alterações de layout porque existem eventos de redimensionamento de tela (por exemplo, alteração de resolução do monitor ou conexão remota com um PC) que não provocam alterações no estado de exibição. Além disso, é uma boa estratégia de programação assegurar que o código lide com as alterações de layout em um único lugar, em vez de usar vários códigos a serem executados para diferentes eventos de alteração de tela.

Por exemplo, digamos que você queira escrever um aplicativo que baixe imagens de plano de fundo de tamanhos diferentes dependendo da resolução de tela atual. No modo ajustado, você deverá baixar uma imagem pequena para se ajustar lado a lado no plano de fundo e no modo preenchido você deverá usar uma imagem com a proporção 4:3 padrão ou uma imagem com a proporção 16:9 no modo paisagem de tela inteira. Além disso, dependendo da altura da tela, você poderá selecionar diferentes resoluções de imagem para cada proporção.

Seguindo essas orientações, configuramos uma função de retorno de chamada com base em um evento de redimensionamento e, dentro dessa função de retorno de chamada, usamos uma API do WinRT para consultar o estado de exibição atual, como mostrado aqui:

JavaScript

 function handleResize(eventArgs) {
    var currentViewState = Windows.UI.ViewManagement.ApplicationView.value;
    var appHeight = eventArgs.view.outerHeight;
    var appWidth = eventArgs.view.outerWidth;

    // downloadImage requires accurate view state and app size!
    downloadImage(currentViewState, appHeight, appWidth);
}

window.addEventListener("resize", handleResize);

 

C#

 private void OnWindowSizeChanged(object sender, Windows.UI.Core.WindowSizeChangedEventArgs e)
{
    var CurrentViewState = Windows.UI.ViewManagement.ApplicationView.Value;
    double AppWidth = e.Size.Width;
    double AppHeight = e.Size.Height;

    // DownloadImage requires accurate view state and app size!
    DownloadImage(CurrentViewState, AppHeight, AppWidth);
}

Window.Current.SizeChanged += OnWindowSizeChanged;

Por outro lado, se consultássemos o tamanho da área de exibição do aplicativo em uma função de retorno de chamada disparada por uma alteração de estado de exibição, obteríamos as informações de estado de exibição corretas, mas o tamanho da área de exibição do aplicativo não estaria atualizado ainda. Portanto, nessas circunstâncias, se nosso aplicativo migrasse de ajustado para paisagem de tela inteira, a AppWidth (largura do aplicativo) poderia ser de 320px e o estado de exibição poderia estar na paisagem de tela inteira. Se passarmos esses valores para DownloadImage, baixaremos o tamanho de imagem errado!

A orientação para o uso de retorno de chamada disparado por eventos de redimensionamento se aplica a outros cenários também. Por exemplo, em JavaScript, se quiser alterar o layout do controle de ListView de uma Grid (grade) para List (lista) dependendo do estado de exibição, isso será possível se você definir que uma chamada de retorno ocorra quando o estado de exibição alterar. No entanto, definir o layout do ListView antes do redimensionamento da tela provocaria dois cálculos de layout para o controle de ListView - um antes do redimensionamento de tela e outro depois. (O controle de WinJS ListView lida automaticamente com eventos de redimensionamento, mas não com os eventos de alteração de estado de exibição.) Ao contrário do exemplo do DownloadImage que vimos, o usuário pode não ser capaz de ver diretamente a diferença, mas o tempo extra que o aplicativo leva para o layout o tornaria mais lento e com uma capacidade de resposta menor. Portanto, é melhor esperar por um retorno de chamada como consequência do redimensionamento de tela antes de consultar o estado de exibição atual e de definir o layout de ListView:

JavaScript

 function handleResize(eventArgs) {
    var isSnapped = (Windows.UI.ViewManagement.ApplicationView.value === 
Windows.UI.ViewManagement.ApplicationViewState.snapped);
    listView.layout = isSnapped ? new WinJS.UI.ListLayout() : new WinJS.UI.GridLayout();
}

window.addEventListener("resize", handleResize);

Para a XAML, para alternar entre esses diferentes estados, use as APIs do VisualStateManager (VSM) para definir qual elementos de XAML devem ser exibidos para exibições individuais. Se você estiver usando as ferramentas do Visual Studio 2011 Beta, é possível ver um exemplo dessas APIs definidas nos modelos de projeto para o modelo de Grid App:

XAML

 <VisualStateManager.VisualStateGroups>
    <!-- Visual states reflect the application's view state -->
    <VisualStateGroup>
        <VisualState x:Name="FullScreenLandscape"/>
        <VisualState x:Name="Filled"/>

        <!-- The entire page respects the narrower 100-pixel margin convention for portrait -->
        <VisualState x:Name="FullScreenPortrait">
            <!-- definition of what UI elements should display or change would go here in Storyboard 
elements -->
        </VisualState>

        <!-- The back button and title have different styles when snapped, and the list representation 
is substituted for the grid displayed in all other view states -->
        <VisualState x:Name="Snapped">
            <!-- definition of what UI elements should display or change would go here in Storyboard 
elements -->
        </VisualState>
    </VisualStateGroup>
</VisualStateManager.VisualStateGroups>

Observe os grupos de VisualState definidos para diferentes estados de exibição. O seu código pode, portanto, alterá-los quando o estado tiver sido alterado em seu evento SizeChanged:

C#

 private void OnWindowSizeChanged(object sender, Windows.UI.Core.WindowSizeChangedEventArgs e)
{
    // get the view state after the size has changed
    string CurrentViewState = Windows.UI.ViewManagement.ApplicationView.Value.ToString();
 
    // using VisualStateManager make sure we navigate to the correct state definition
    VisualStateManager.GoToState(this, CurrentViewState, false);
}

Como se pode ver nesse exemplo, usar VSM combinado com APIs de SizeChanged e ApplicationView oferece um mecanismo flexível para adaptar as alterações de layout de tela.

Conclusão

Nesta postagem, vimos como é possível detectar eventos de redimensionamento de tela e alterações de estado de exibição no código. Para o Consumer Preview, recomendo que você siga as alterações de evento de tamanho de tela antes de consultar o WinRT para obter informações do estado de exibição, como acabei de fazer aqui. Se você estiver seguindo essas orientações, o seu código verá o tamanho de tela atual e as informações do estado de exibição corretos cada vez que o aplicativo for redimensionado. Para obter mais exemplo, confira nosso exemplo do Windows 8 SDK. Também convidamos você a comentar sobre esse tópico!

--Chris Jones, gerente de programas, Windows

Agradecimentos especiais a Tim Heuer, que ajudou a elaborar esta postagem do blog.