(译)使用更多的像素——Windows 8 屏幕和视觉状态适配
本文同步发表于:WP7开发论坛 Windows Phone Developer Network: http://www.wpdevn.com/showtopic-115.aspx
在Windows 8 你的应用运行在不同的屏幕尺寸和视图状态中。 用户可以将你的应用运行在一个 25寸台式机显示器上,也可以将它运行在一个10寸的宽屏平板设备上。无论在什么样的情况下,你始终希望你的应用可以充分使用所有的可用控件。在这片文章中,我将告诉你如何在应用中跟踪屏幕大小和视觉状态,同时给你一些关于在编写win8客户预览版应用中处理处理屏幕大小和视觉状态改变的建议。 在Build 大会中我们提供一些关于如何设计你的应用以适应不同的屏幕场景的建议,你可以在这里看到 XMAL 和 HTML 的建议
最近在 Buding Windows 8 Blog 我们分享了一些关于屏幕缩放的研究和设计思想。 通常你可以只是用标记(标记语言?) ( use pure markup) 去适配各种屏幕尺寸无需专门去写一些代码。 但是有时候你需要时刻跟踪你的应用所处于的 视觉状态,无论你的应用是在 portrait, full-screen, filled, snapped 模式你都需要,写相应的代码做出响应。例如: 如果你使用 HTML 的ListView 来显示一堆Items 你也许 希望在FullScreen 模式中使用个GridLayout ,在Snapped 模式中使用 ListLayout ,在XAML 中你也许同样希望在GridView 和 ListView中切换。为了弄清如何实现这功能,我么来看看如何检查缩放和视觉的变化。
左侧的Full Screen 的视觉状态中使用了一个 GridLayout (HTML)/GridView (xmal)
右侧的Snapped 视觉装弹中使用了List Layout(HTML)/ListView (XAML)
屏幕缩放和视觉装弹基础 (The basics of resize and view state changes)
在Windows 8 中使用 XMAL 和 HTML 处理屏幕缩放和 视觉状态变化的技术模式是一样的: 只需要简单的为在各自框架中所提供的事件提供回调函数和一些必要的查询数据。
例如: 在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 应用时, 你同样可以使用Win RT 来直接查询当前的视觉状态 Win Rt 提供了个描述应用视觉状态的 枚举
JavaScript
var currentViewState = Windows.UI.ViewManagement.ApplicationView.value;
c#
var CurrentViewState = Windows.UI.ViewManagement.ApplicationView.Value;
同样 使用JavaScript 写的Windows8 应用支持msMatchMedia 方法 ,使用DOM 窗口对象 可以用于 a condition with multiple media queries (啥意思。。。。 )例如: 1600像素宽的全屏景观模式(full-screen landscape )
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);
在客户预览版中的 缩放和视觉状态(Resize and view state in consumer preview)
现在我们已经了解了如何访问视觉状态屏幕尺寸的基础方法。现在来讨论下如何使用这些功能来处理屏幕缩放(screen resize )。 在Window 8 客户预览版中,订阅缩放事件(resize event)和视觉状态事件(view state event)的触发顺序是确定的, 视觉状态变化事件(和相关的回调函数)总是发生在缩放事件(resize event),因为你总是必须等待在触发缩放事件(resize event)之前访问当前的视觉状态。 这将给你一个简单和统一的途径在代码中去处理尺寸和 视觉状态的改变。 在等待缩放事件(resize event) 触发(和等待任何随同的回调函数调用) 你可以确定返回的显示区域和视觉状态信息是同步的。
我同样建议 你可以使用缩放事件(resize event)去处理layout 的改变(you use resize events to trigger code that handles layout changes)因为有一些缩放事件(resize event ) (例如: 修改显示器分辨率和远程连接到一个PC) 并不会倒是视觉状态改变。此外,这是一个好的开发方法用来确保代码是在同一的地方处理layout 的变化,即便有不同的代码被不懂的屏幕改变事件(screen chnage event) 调用。
比如: 你想写一个根据当前屏幕分辨率大小下载不同的背景图片的应用。在Snapped模式中 你也许希望下载一个小的瓷贴悲剧图, 在filled 模式中 你希望是一个4:3 的图或者是一个用户full screen-landscape模式中的16:9 图片。同时你想根据不同的屏幕高度选择不同的图片分辨率 以满足不同的高宽比。
接下来的指导中,我们写了个缩放事件(resize event )回调函数,这个函数使用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;
相比之下, 我们在视觉状态变化时触发的回调函数中查询应用显示区域大小( we were to query the app display area size in a callback function triggered by a view state change)我们需要获得当前的视觉状态信息,但是应用显示区域大小并不会立即更新。 在这样的情况下, 如果我们的应用从snapped 模式过渡到 fullscreen-landscape 模式,应用宽也许是320 像素视觉状态也许是fullscreen-landscape. 如果我们根据这些信息去下载图片我们将得到一个错误的图片。
这个缩放事件(resize event )触发回调的方式适用于太多的其他情况。比如: 在JavaScirpit中 如果你希望修改根据视觉状态修改ListView的部署从Grid 到List,那么你需要设置一个视觉状态改变的回调。 但是在屏幕改变之前设置ListView 布局会导致将两个布局传给了ListView ——一个是屏幕改变之前的一个是之后的(WinJs ListView 会自动处理缩放事件(resize event)但是不会处理视觉状态改变事件(view state change event ) )。 还是之前那个下载图片的例子, 用户也许不会直接看到这个区别, 但是应用将会开销更多的时间处理布局,将导致运行缓慢和相应延迟。 所以 较好的方式是等待回调, 由于屏幕改变是在你查询当前视觉状态之前然后设置相应的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中 个人的意见是: 在不同的视觉状态切花是使用 View State Manager(VSM) API 去定义不同的视觉状态元素。 如果你使用 Visual Studio 201 Beta 你可以看见一个在程序模板中的Grid APP template 中定义这些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 Group 是为不同的视觉状态定义的。 当状态改变时可以在代码中的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); }
如你所看到的在这例子中使用VSM 结合 SizeChanged 和 ApplicationView API 提供了个灵活的机制以适应屏幕变化
结论:
在本文中我们讨论了如何检测屏幕变化事件 和 视觉状态事件, 在客户预览版中我们建议你 在屏幕大小改变前通过WinRT API 查询视觉状态信息。如果你遵循这些建议你的代码能获取到正确的屏幕尺寸和视觉状态。要进看更多的例子可以看 Windows 8 SDK sample 。我们同样邀请你就有关此主题的进一步思考和反馈!
--Chris Jones, Program Manager, Windows
With special thanks to Tim Heuer, who helped craft this blog post.
本文同步发表于:WP7开发论坛 Windows Phone Developer Network: http://www.wpdevn.com/showtopic-115.aspx