最大程度地利用像素,适应视图状态的变更___转

http://blogs.msdn.com/b/windowsappdev_cn/archive/2012/04/25/getting-your-pixels.aspx

在 Windows 8 中,您的应用程序将在各种屏幕尺寸和不同视图状态下运行。用户可能将应用程序分屏显示于 25 英寸的台式计算机显示器的一侧,也可能将其全屏显示于 10 英寸的宽屏平板设备。但是无论是哪种情形,您都希望您的应用程序能够充分利用可用空间。在本篇博文中,我将向您展示如何在代码中跟踪您应用程序的当前尺寸和视图状态,并为您提供一些有关在 Windows 8 Consumer Preview 中编写应用程序的技巧,从而让您轻松应对屏幕尺寸和视图状态的变更。

在 //build/ 大会上,我曾向您介绍了如何为不同的屏幕应用场景而设计应用程序(例如,请观看视频 XAML talkHTML talk)。此外,最近我们也在 Building Windows 8 博客中与您分享了一些有关屏幕缩放的研究内容和设计想法。通常情况下,您可使用纯标记来适应屏幕尺寸的变更,而无需编写显示代码。但有时您需要跟踪应用程序处于何种视图状态(即确定应用程序是处于纵向、全屏、填充抑或辅屏模式),并编写代码做出相应响应。例如,如果您正在使用一项 HTML ListView 来显示项目,那么您可能希望在全屏模式时使用 GridLayout,而在辅屏模式时使用 ListLayout。(如下图所示。)而对于 XAML,您可能希望在 GridView 控件和 ListView 控件间进行类似的切换。为明确应如何进行这一操作,让我们一起来看看应如何在代码中检测尺寸调整和视图状态的变更。

全屏视图的天气预报应用程序显示了 3 列磁贴,其中每列均包含 3 个磁贴,成网格状排列;而右侧的辅屏视图则将相同的磁贴排列成一列。

左侧全屏视图状态中设置了网格布局 (HTML) 或 GridView 控件 (XAML):
右侧辅屏视图状态中设置了列表布局 (HTML) 或 ListView 控件 (XAML)。

尺寸调整和视图状态变更的基础知识

对于使用 XAML 和 HTML 编写的 Windows 8 应用程序,其处理屏幕尺寸调整和视图状态变更的基本模式都是一样的:只需为各自框架所提供的相应事件附加回调函数,并查询任何其他必要的信息即可。

例如在 JavaScript 中,您可为基本窗口尺寸调整事件而创建一个处理程序,如下一代码示例所显示的,这其实是一个简单的回调函数。您可使用该事件来检测何时为调整过尺寸的应用程序显示区域,并查找该应用程序新区域的尺寸。

JavaScript

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

window.addEventListener("resize", handleResize);

在 XAML 中,您可类似地在当前窗口上使用 SizeChanged 事件来设置一个事件处理程序:

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;

在为 Windows 8 应用程序编程过程中,您同时可使用 WinRT 来直接查询当前的视图状态。WinRT 将提供一个枚举值,您可通过该值了解某应用程序的当前视图状态。

JavaScript

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

C#

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

使用 JavaScript 编写的 Windows 8 应用程序同时可支持 msMatchMedia 函数,该函数通过 DOM 窗口对象进行运算,当您拥有多个媒体查询时(例如横向全屏与拥有 1600 像素的屏幕宽度相结合),该函数将十分有效:

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);

在 Consumer Preview 中调整尺寸与视图状态

现在我们已经了解了有关如何获取视图状态和屏幕尺寸信息的基础知识,接下来让我们一同来探讨如何部署这一功能来应对屏幕尺寸的调整。在 Windows 8 Consumer Preview 中,尺寸调整事件与视图状态变更事件的顺序是确定的,因此视图状态事件(以及相关的回调函数)始终发生在尺寸调整事件之前。正因如此,您必须始终在访问当前视图状态前等待需启动的尺寸调整事件。这将为您提供一个简便、统一的方法,让您在代码中处理尺寸与视图状态的变更。由于您已经等待了需启动的尺寸调整事件(以及需调用的相关回调函数),因此您可确信当前显示区域所返回的信息与视图状态是同步的。

同时,我建议您使用尺寸调整事件来触发用于处理布局变更的代码,这是因为有几个屏幕尺寸调整事件将不会引起视图状态的变更(例如显示器分辨率的变更或面向 PC 的远程连接)。此外,将处理布局变更的代码放置于同一位置是一项优秀的编程做法,您应避免为不同屏幕变更事件而调用不同的代码。

例如,假设您希望编写一个应用程序,并利用该应用程序根据当前屏幕分辨率而下载不同尺寸的背景图像。在辅屏模式中,您可能希望为背景中的磁贴下载一个较小的图像,在填充模式中,您可能希望下载一个纵横比为 4:3 的标准图像,而在宽屏纵向模式中,您可能希望下载一个纵横比为 16:9 的图像。此外,由于屏幕高度的不同,您可能希望为纵横比不同的屏幕选择不同的图像分辨率。

根据这一指导原则,我们基于尺寸调整事件而设置了回调函数,并在该回调函数内使用 WinRT API 来查询当前视图状态,详情如下:

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;

相反,如果我们在由视图状态变更而触发的回调函数中查询应用程序的显示区域,那么我们将获得正确的视图状态信息,但是应用程序显示区域的尺寸至今都无法更新。因此,在这些情形下,如果我们的应用程序从辅屏显示转变成纵向全屏显示,那么 AppWidth 可能为 320px,而视图状态可能为纵向全屏。如果我们将这些值传递至 DownloadImage,那么我们将下载尺寸错误的图像!

有关使用由尺寸调整事件而触发的回调的指导原则同样适用于其他应用场景。例如,在 JavaScript 中,如果您希望根据视图状态而将 ListView 控件的布局从网格变更为列表,那么您可在视图状态变更时设置发生一项回调。但是在屏幕尺寸调整之前设置 ListView 布局可能导致对 ListView 控件发生两次布局过程,其中一次发生于屏幕尺寸调整之前,另一次发生于屏幕尺寸调整之后。(WinJS ListView 控件将自动处理尺寸调整事件,但并不会处理视图状态变更事件。)与我们此前所看到的 DownloadImage 示例不同,用户可能无法直接看到其中的差异,但是应用程序设置布局所耗费的额外时间将降低应用程序的运行速度和响应程度。因此,在您查询当前视图状态和相应设置 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);

对于 XAML,如需在这些不同的状态间进行切换,请使用 VisualStateManager (VSM) API 来定义应为单个视图而显示的 XAML 元素。如果您正在使用 Visual Studio 2011 Beta 工具,那么您可在项目模板中查看为 Grid App 模板而定义的 API 示例:

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>

请注意为不同视图状态而定义的 VisualState 组。当状态在 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);
}

从以上示例中可以看出,使用与 SizeChangedApplicationView API 合并的 VSM 可为您提供一个灵活的机制来适应屏幕布局的变更。

结论

在本篇博文中,我们一同了解了如何在代码中检测屏幕尺寸调整事件和视图状态的变更。对于 Consumer Preview,我建议您效仿我的做法,在查询 WinRT 获取视图状态信息之前侦听屏幕尺寸事件的变更。如果您能遵循该指导原则,那么每当应用程序尺寸调整时,您的代码都将显示出正确的当前屏幕尺寸和视图状态信息。欲查看更多示例,请查看我们的 Windows 8 SDK 示例。我们同时期待获得您有关该主题的观点和反馈!

-- Windows 项目经理 Chris Jones,

posted on 2012-09-04 14:15  GIS-MAN  阅读(258)  评论(0编辑  收藏  举报

导航