Metro Style App (5) 針對不同瀏覽模式開發

在 Windows 8 中已經對多瀏覽模式以及多解析度相容,那在開發 Metro Style App 的時候也不能只針對一種畫面做調整,還必須考量到行動裝置或是桌上型電腦的操作使用,讓開發出來的 Metro Style App 能夠更容易操作。Metro Style App 的瀏覽模式在 Metro Style Design 已經有介紹過。

開發工具

如果要針對多瀏覽模式做開發,當然有各種裝置一定是最方便了,可以直接體會操作的感覺。不過 Metro Style App 支援的規格這麼多,怎麼可能每一台都有。在 Visual Studio 11 中也提供了非常好用的模擬器(必須要在 Windows 8 環境下的才有)。

image

在 Debug 的時候有三種模式可以選擇,Local Machine 是直接在 App 掛載在本機執行,Simulator 就是模擬器了,而 Remote Machine 則是如果有其他裝置,只要用網路線將開發環境跟測試裝置相連,就可以在測試裝置上啟動 Debug 偵錯。Running Windows Metro style apps on a remote machine 這邊有利用 Remote 裝置的完整步驟。如果用模擬器執行的話。

image

會再另外開一個模擬器的視窗來執行,這個模擬器的畫面主要是根據平板來顯示的,右側的功能鍵也有模擬手指功能、翻轉、調整解析度等等,模擬器本身就是一個完整的環境,有在機器上安裝的工具也都可以在模擬器中找到。

image

既然有好的模擬器可以使用,那就可以來針對 Metro Style App 支援的顯示模式來做支援。

  • 水平以及直立顯示

  • Snapped 模式

  • Semantic Zoom

Snapped 模式

Snapped 模式也是 Metro UI 獨有的,因為在 Metro UI 下預設一次只能開啟一個 App,想像一下 IOS 應該就了解了,如果今天想要邊聊 MSN 邊上網那在 iPad 上就是要一直切換來切換去的,手機上影響可能比較不大,因為畢竟螢幕也小,也沒辦法顯示那麼多資訊。

  1. 先進入一個 APP
  2. 指標移到左上再往下會顯示全部正在執行的 APP
  3. 選取其中一項並且拖拉到視窗邊

image

image

image

基本上 Grid Application 已經有預設 Snapped Mode 的顯示方式了,而這邊的做法正是使用到 HTML5 裡面的 media query 來做到在 Snapped Mode 跟一般模式下面的區別。在相對應的 css 徵可以找到以下的區段。

@media screen and (-ms-view-state: snapped) {
...
}

這中間的區段也就是當進入 Snapped 的時候要額外套用的部分。

Semantic Zoom

Semantic Zoom 是當希望可以不用改變層級的狀況下去修改資訊的顯示方式,有可能是單一頁面資訊太多的時候,可以使用 zoom-in 的方式顯示全部資料方便找尋。

image

這是 Metro UI 開始畫面的 zoom-in 結果,會顯示出全部的 APP,也可以直接點選分群之後移到點選的群組位置。

image

修改 groupedItemsPage.html

找到最下面的 section aria-label=”Main content”  區間修改為

<section aria-label="Main content" role="main">
<div id="zoom" data-win-control="WinJS.UI.SemanticZoom" data-win-options="{ initiallyZoomedOut: false }"
style="height: 100%">
<div id="zoomedInListView" class="groupeditemslist" aria-label="List of groups" data-win-control="WinJS.UI.ListView"
data-win-options="{ selectionMode: 'none' }"></div>
<div id="zoomedOutListView" class="groupeditemslist" aria-label="List of groups"
data-win-control="WinJS.UI.ListView" data-win-options="{ selectionMode: 'none' }">
</div>
</div>
</section>

原本只有一個 ListView  改為兩個 ListView 分別對 zoom-in ,zoom-out 做支援。

修改 groupedItemsPage.js

在 groupDataSelector 增加會在 zoom-in 需要的回傳

groupDataSelector: function (item) {
return {
title: item.group.title,
shortTitle: item.group.shortTitle,
backgroundImage: item.group.backgroundImage,
click: function () {
nav.navigate("/html/groupDetailPage.html", { group: item.group });
}
}
},

修改 itemInvoked function

itemInvoked: function (eventObject) {
// Determine whether the SemanticZoom control is zoomed out
var zoomedOut = document.querySelector("#zoom").winControl.zoomedOut;

if (appView.value === appViewState.snapped) {
// If the page is snapped, the user invoked a group.
var group = data.groups.getAt(eventObject.detail.itemIndex);
nav.navigate("/html/groupDetailPage.html", { group: group });
} else {
// If the page is not snapped, the user invoked an item.
var item = data.items.getAt(eventObject.detail.itemIndex);
nav.navigate("/html/itemDetailPage.html", { item: item });
}
},

修改 ready function

ready: function (element, options) {
var listViews = element.querySelectorAll(".groupeditemslist");

for (var i = 0; i < listViews.length; i++) {
var listView = listViews[i].winControl;

ui.setOptions(listView, {
groupHeaderTemplate: element.querySelector(".headerTemplate"),
itemTemplate: element.querySelector(".itemtemplate"),
oniteminvoked: this.itemInvoked
});
}

this.updateLayout(element, appView.value);
},

還要修改 updateLayout function

// This function updates the page layout in response to viewState changes.
updateLayout: function (element, viewState) {
var list = data.items.createGrouped(this.groupKeySelector, this.groupDataSelector);

if (viewState === appViewState.snapped) {
// If the page is snapped, display a list of groups.
var listViews = element.querySelectorAll(".groupeditemslist");

for (var i = 0; i < listViews.length; i++) {
var listView = listViews[i].winControl;

ui.setOptions(listView, {
itemDataSource: list.groups.dataSource,
groupDataSource: null,
layout: new ui.ListLayout()
});
}
} else {
// If the page is not snapped, display a grid of grouped items.
// For the zoomed-in ListView, show groups and items
var zoomedInListView = element.querySelector("#zoomedInListView").winControl;

ui.setOptions(zoomedInListView, {
itemDataSource: list.dataSource,
groupDataSource: list.groups.dataSource,
layout: new ui.GridLayout({ groupHeaderPosition: "top" })
});

// For the zoomed-out ListView, show groups only
var zoomedOutListView = element.querySelector("#zoomedOutListView").winControl;

ui.setOptions(zoomedOutListView, {
itemDataSource: list.groups.dataSource,
groupDataSource: null,
layout: new ui.GridLayout({ groupHeaderPosition: "top" })
});
}
}

增加 groupedItemsPage.css

加入 zoom-in 的 css

#zoomedOutListView {
margin-left: 70px;
}

在 Simulater 中測試 Semantic Zoom

在右上角可以找到兩隻手指的模擬按鈕

image

在畫面上點下滑鼠並且滾輪往後收合到事件被觸發為止,滑鼠必須一直維持點擊狀態。

image

原本的 Grouped-detail 畫面

image

zoom-in 之後的 Grouped-detail 畫面

image

這邊畫面可能看起來很像,不過在 zoom-out 的時候一張圖代表一個 item ,zoom-in 之後代表是一個 group。直接反向操作 zoom-in 的動作就是 zoom-out 了

Summary

其實這邊並沒有硬性規定開發者要怎麼去做,微軟是希望 Metro UI Design 的想法來開發 APP,但是並沒有那麼硬性。畫面操作方面微軟也號稱完整支援 HTML5,所以其實這邊還有很多發揮的空間,有很多不一樣的版面特效需求都是可以被實現的。

發表迴響

你的電子郵件位址並不會被公開。 必要欄位標記為 *