AppBar大量的Metro应用里面使用,那么这里有一个很基本的问题:AppBar需要在屏幕中占用一定的空间。那么会不会当AppBar显示的时候,某些东西被AppBar盖住了呢?
比如,应用里面有个listview,这个listview的底部接近屏幕的底部,那么当AppBar显示的时候,listview底部的一部分会被AppBar盖住,从而使得用户无法看到那部分东西,这显然是一个很不好的现象。MSDN上专门有一个页面来描述这个问题,http://msdn.microsoft.com/zh-cn/library/windows/apps/jj649138.aspx。这也说明这是个普遍问题。
其实解决这个问题的关键在于AppBar的2个消息:beforeshow和beforehide。
在AppBar显示前,把ListView的高度缩小一点,在AppBar隐藏前,将ListView的高度恢复到原始高度。
先来看看HTML代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>pagecontrol</title>
<!-- WinJS references -->
<link href="//Microsoft.WinJS.1.0/css/ui-dark.css" rel="stylesheet" />
<script src="//Microsoft.WinJS.1.0/js/base.js"></script>
<script src="//Microsoft.WinJS.1.0/js/ui.js"></script>
<link href="/css/pagecontrol.css" rel="stylesheet" />
<script src="/js/pagecontrol.js"></script>
<script src="/js/appbar.js"></script>
</head>
<body>
<!-- Full screen container for ListView -->
<div id="scenarioFullscreen">
<header style="text-align:center;margin-top:80px">Test listview + appbar</header>
<section style="height:720px;margin-top:40px">
<div id="scenarioListView" style="height:100%"
data-win-control="WinJS.UI.ListView"
data-win-options="{ itemTemplate: smallListIconTextTemplate, selectionMode: 'multi', tapBehavior: 'toggleSelect', swipeBehavior: 'select', layout: { type: WinJS.UI.ListLayout, maxRows: 100 },itemDataSource : DataExample.itemList.dataSource }" >
</div>
</section>
</div>
<!-- AppBar with contextual commands for a ListView -->
<!-- BEGINTEMPLATE: Template code for AppBar -->
<div id="scenarioAppBar" data-win-control="WinJS.UI.AppBar">
<button data-win-control="WinJS.UI.AppBarCommand" data-win-options="{id:'cmdAdd',label:'Add',icon:'add',section:'global',extraClass:'singleSelect',tooltip:'Add item'}"></button>
<button data-win-control="WinJS.UI.AppBarCommand" data-win-options="{id:'cmdSelectAll',label:'Select All',icon:'selectall',section:'selection',extraClass:'ContextRelated',tooltip:'Select All'}"></button>
<button data-win-control="WinJS.UI.AppBarCommand" data-win-options="{id:'cmdClearSelection',label:'Clear Selection',icon:'clearselection',section:'selection',extraClass:'ContextRelated',tooltip:'Clear Selection'}"></button>
<hr data-win-control="WinJS.UI.AppBarCommand" data-win-options="{type:'separator',section:'selection',extraClass:'ContextRelated'}" />
<button data-win-control="WinJS.UI.AppBarCommand" data-win-options="{id:'cmdDelete',label:'Delete',icon:'delete',section:'selection',extraClass:'ContextRelated',tooltip:'Delete item'}"></button>
</div>
<!-- ENDTEMPLATE -->
</body>
</html>
简单的加了一个ListView和一个AppBar。ListView是一个非常有用,也非常灵活的控件,具体可以参考:http://msdn.microsoft.com/zh-cn/library/windows/apps/hh465465.aspx
这里就是一个简单应用。
给这个listview加一些测试数据,看js代码:
(function () {
"use strict";
var dataArray = [
{ title: "Basic banana", text: "Low-fat frozen yogurt", picture: "images/60banana.png" },
{ title: "Banana blast", text: "Ice cream", picture: "images/60banana.png" },
{ title: "Brilliant banana", text: "Frozen custard", picture: "images/60banana.png" },
{ title: "Orange surprise", text: "Sherbet", picture: "images/60orange.png" },
{ title: "Original orange", text: "Sherbet", picture: "images/60orange.png" },
{ title: "Vanilla", text: "Ice cream", picture: "images/60vanilla.png" },
{ title: "Very vanilla", text: "Frozen custard", picture: "images/60vanilla.png" },
{ title: "Marvelous mint", text: "Gelato", picture: "images/60mint.png" },
{ title: "Succulent strawberry", text: "Sorbet", picture: "images/60strawberry.png" },
{ title: "Basic banana", text: "Low-fat frozen yogurt", picture: "images/60banana.png" },
{ title: "Banana blast", text: "Ice cream", picture: "images/60banana.png" },
{ title: "Brilliant banana", text: "Frozen custard", picture: "images/60banana.png" },
{ title: "Orange surprise", text: "Sherbet", picture: "images/60orange.png" },
{ title: "Original orange", text: "Sherbet", picture: "images/60orange.png" },
{ title: "Vanilla", text: "Ice cream", picture: "images/60vanilla.png" },
{ title: "Very vanilla", text: "Frozen custard", picture: "images/60vanilla.png" },
{ title: "Marvelous mint", text: "Gelato", picture: "images/60mint.png" },
{ title: "Succulent strawberry", text: "Sorbet", picture: "images/60strawberry.png" },
{ title: "Basic banana", text: "Low-fat frozen yogurt", picture: "images/60banana.png" },
{ title: "Banana blast", text: "Ice cream", picture: "images/60banana.png" },
{ title: "Brilliant banana", text: "Frozen custard", picture: "images/60banana.png" },
{ title: "Orange surprise", text: "Sherbet", picture: "images/60orange.png" },
{ title: "Original orange", text: "Sherbet", picture: "images/60orange.png" },
{ title: "Vanilla", text: "Ice cream", picture: "images/60vanilla.png" },
{ title: "Very vanilla", text: "Frozen custard", picture: "images/60vanilla.png" },
{ title: "Marvelous mint", text: "Gelato", picture: "images/60mint.png" },
{ title: "Succulent strawberry", text: "Sorbet", picture: "images/60strawberry.png" },
{ title: "lastitem", text: "test", picture: "images/60strawberry.png" }
];
var dataList = new WinJS.Binding.List(dataArray);
// Create a namespace to make the data publicly
// accessible.
var publicMembers =
{
itemList: dataList
};
WinJS.Namespace.define("DataExample", publicMembers);
})();
搞了一些测试代码,然后创建一个成员dataList,并且通过WinJS.Namespace暴露出来。这样在HTML里面就可以把ListView和这些数据绑定起来,就是设置一个属性:
itemDataSource : DataExample.itemList.dataSource
这样,我们就可以显示这么个界面:

这个list的底部已经接近屏幕的底部了,如果不做特殊处理,那么当AppBar显示的时候,list底部一部分就被盖住了。
先看一下beforeshow的响应函数:
function doAppBarShow() {
var listView = document.getElementById("scenarioListView");
var appBar = document.getElementById("scenarioAppBar");
var appBarHeight = appBar.offsetHeight;
// Move the scrollbar into view if appbar is sticky
if (appBar.winControl.sticky) {
var listViewTargetHeight = "calc(100% - " + appBarHeight + "px)";
var transition = {
property: 'height',
duration: 367,
timing: "cubic-bezier(0.1, 0.9, 0.2, 0.1)",
to: listViewTargetHeight
};
WinJS.UI.executeTransition(listView, transition);
}
}
这个函数就做了一件事情,当AppBar是sticky(就是一直显示着)的时候将ListView高度缩小一点(缩小部分比AppBar的高度稍微大一点)。
beforehide对应的函数:
function doAppBarHide() {
var listView = document.getElementById("scenarioListView");
var appBar = document.getElementById("scenarioAppBar");
var appBarHeight = appBar.offsetHeight;
// Move the scrollbar into view if appbar is sticky
if (appBar.winControl.sticky) {
var listViewTargetHeight = "100%";
var transition = {
property: 'height',
duration: 367,
timing: "cubic-bezier(0.1, 0.9, 0.2, 0.1)",
to: listViewTargetHeight
};
WinJS.UI.executeTransition(listView, transition);
}
}
当AppBar不是Sticky的时候,将ListView恢复到原来的高度。
当用户点击ListView里面的某一项时候,会触发iteminvoked的消息,给它绑定一个函数:
function doSelectItem() {
var appBarDiv = document.getElementById("scenarioAppBar");
var appBar = document.getElementById('scenarioAppBar').winControl;
var listView = document.getElementById("scenarioListView").winControl;
var count = listView.selection.count();
if (count > 0) {
// Show selection commands in AppBar
appBar.showCommands(appBarDiv.querySelectorAll('.ContextRelated'));
appBar.sticky = true;
appBar.show();
} else {
// Hide selection commands in AppBar
appBar.hide();
appBar.hideCommands(appBarDiv.querySelectorAll('.ContextRelated'));
appBar.sticky = false;
}
}
也就是说当用户选择了一项或者多项的时候,显示class是ContextRelated的按钮,并且将AppBar设置成Sticky模式,然后显示AppBar。反之,如果用户没有选中任何项,则改成非Sticky的,隐藏ContextRelated的按钮并且隐藏AppBar。
比如:用户点击了ListView里面的某一项,那么就会显示AppBar,然后再点一次,这个时候就没有任何选中项了,就会隐藏AppBar。
initAppBar用来处理按钮的响应函数:
function initAppBar() {
var appBarDiv = document.getElementById("scenarioAppBar");
var appBar = document.getElementById("scenarioAppBar").winControl;
// Add event listeners
document.getElementById("cmdAdd").addEventListener("click", doClickAdd, false);
document.getElementById("cmdDelete").addEventListener("click", doClickDelete, false);
document.getElementById("cmdSelectAll").addEventListener("click", doClickSelectAll, false);
document.getElementById("cmdClearSelection").addEventListener("click", doClickClearSelection, false);
appBar.addEventListener("beforeshow", doAppBarShow, false);
appBar.addEventListener("beforehide", doAppBarHide, false);
// Hide selection group of commands
appBar.hideCommands(appBarDiv.querySelectorAll('.ContextRelated'));
// Disable AppBar until in full screen mode
var listView = document.getElementById("scenarioListView").winControl;
listView.addEventListener("iteminvoked", doSelectItem);
}
这个函数里面绑定了应用栏按钮的响应函数,还有beforeshow和beforehide两个事件的响应函数和ListView的iteminvoked事件。
在ready函数里面调用一下这个函数:
var page = WinJS.UI.Pages.define("pagecontrol.html", {
ready: function (element, options) {
initAppBar();
},
});
这样,当用户选择ListView里面的某一项的时候:
1. doSelectItem会被调用,doSelectItem会根据是否有选中项来显示/隐藏AppBar;
2. AppBar显示前会调用doAppBarShow,doAppBarShow会将ListView的高度缩小一点;
3. AppBar隐藏前会调用doAppBarHide,doAppBarHide会将ListView高度复原。
这样就解决了ListView底部被AppBar覆盖的问题,其实ListView只是一种例子,其他的控件也会有被覆盖的问题,解决的办法是类似的(当然有时被覆盖一下也不要紧)。
效果:

可以看到ListView的底部显示在AppBar的上面了,这样就不会被盖住了。
完整js代码:
(function () {
"use strict";
var page = WinJS.UI.Pages.define("pagecontrol.html", {
ready: function (element, options) {
initAppBar();
},
});
function initAppBar() {
var appBarDiv = document.getElementById("scenarioAppBar");
var appBar = document.getElementById("scenarioAppBar").winControl;
// Add event listeners
document.getElementById("cmdAdd").addEventListener("click", doClickAdd, false);
document.getElementById("cmdDelete").addEventListener("click", doClickDelete, false);
document.getElementById("cmdSelectAll").addEventListener("click", doClickSelectAll, false);
document.getElementById("cmdClearSelection").addEventListener("click", doClickClearSelection, false);
appBar.addEventListener("beforeshow", doAppBarShow, false);
appBar.addEventListener("beforehide", doAppBarHide, false);
// Hide selection group of commands
appBar.hideCommands(appBarDiv.querySelectorAll('.ContextRelated'));
// Disable AppBar until in full screen mode
var listView = document.getElementById("scenarioListView").winControl;
listView.addEventListener("iteminvoked", doSelectItem);
}
function doClickAdd()
{ }
function doClickDelete()
{ }
function doClickSelectAll()
{ }
function doClickClearSelection()
{ }
function doSelectItem() {
var appBarDiv = document.getElementById("scenarioAppBar");
var appBar = document.getElementById('scenarioAppBar').winControl;
var listView = document.getElementById("scenarioListView").winControl;
var count = listView.selection.count();
if (count > 0) {
// Show selection commands in AppBar
appBar.showCommands(appBarDiv.querySelectorAll('.ContextRelated'));
appBar.sticky = true;
appBar.show();
} else {
// Hide selection commands in AppBar
appBar.hide();
appBar.hideCommands(appBarDiv.querySelectorAll('.ContextRelated'));
appBar.sticky = false;
}
}
/* This function slides the ListView scrollbar into view if occluded by the AppBar (in sticky mode) */
function doAppBarShow() {
var listView = document.getElementById("scenarioListView");
var appBar = document.getElementById("scenarioAppBar");
var appBarHeight = appBar.offsetHeight;
// Move the scrollbar into view if appbar is sticky
if (appBar.winControl.sticky) {
var listViewTargetHeight = "calc(100% - " + appBarHeight + "px)";
var transition = {
property: 'height',
duration: 367,
timing: "cubic-bezier(0.1, 0.9, 0.2, 0.1)",
to: listViewTargetHeight
};
WinJS.UI.executeTransition(listView, transition);
}
}
/* This function slides the ListView scrollbar back to its original position */
function doAppBarHide() {
var listView = document.getElementById("scenarioListView");
var appBar = document.getElementById("scenarioAppBar");
var appBarHeight = appBar.offsetHeight;
// Move the scrollbar into view if appbar is sticky
if (appBar.winControl.sticky) {
var listViewTargetHeight = "100%";
var transition = {
property: 'height',
duration: 367,
timing: "cubic-bezier(0.1, 0.9, 0.2, 0.1)",
to: listViewTargetHeight
};
WinJS.UI.executeTransition(listView, transition);
}
}
})();
(function () {
"use strict";
var dataArray = [
{ title: "Basic banana", text: "Low-fat frozen yogurt", picture: "images/60banana.png" },
{ title: "Banana blast", text: "Ice cream", picture: "images/60banana.png" },
{ title: "Brilliant banana", text: "Frozen custard", picture: "images/60banana.png" },
{ title: "Orange surprise", text: "Sherbet", picture: "images/60orange.png" },
{ title: "Original orange", text: "Sherbet", picture: "images/60orange.png" },
{ title: "Vanilla", text: "Ice cream", picture: "images/60vanilla.png" },
{ title: "Very vanilla", text: "Frozen custard", picture: "images/60vanilla.png" },
{ title: "Marvelous mint", text: "Gelato", picture: "images/60mint.png" },
{ title: "Succulent strawberry", text: "Sorbet", picture: "images/60strawberry.png" },
{ title: "Basic banana", text: "Low-fat frozen yogurt", picture: "images/60banana.png" },
{ title: "Banana blast", text: "Ice cream", picture: "images/60banana.png" },
{ title: "Brilliant banana", text: "Frozen custard", picture: "images/60banana.png" },
{ title: "Orange surprise", text: "Sherbet", picture: "images/60orange.png" },
{ title: "Original orange", text: "Sherbet", picture: "images/60orange.png" },
{ title: "Vanilla", text: "Ice cream", picture: "images/60vanilla.png" },
{ title: "Very vanilla", text: "Frozen custard", picture: "images/60vanilla.png" },
{ title: "Marvelous mint", text: "Gelato", picture: "images/60mint.png" },
{ title: "Succulent strawberry", text: "Sorbet", picture: "images/60strawberry.png" },
{ title: "Basic banana", text: "Low-fat frozen yogurt", picture: "images/60banana.png" },
{ title: "Banana blast", text: "Ice cream", picture: "images/60banana.png" },
{ title: "Brilliant banana", text: "Frozen custard", picture: "images/60banana.png" },
{ title: "Orange surprise", text: "Sherbet", picture: "images/60orange.png" },
{ title: "Original orange", text: "Sherbet", picture: "images/60orange.png" },
{ title: "Vanilla", text: "Ice cream", picture: "images/60vanilla.png" },
{ title: "Very vanilla", text: "Frozen custard", picture: "images/60vanilla.png" },
{ title: "Marvelous mint", text: "Gelato", picture: "images/60mint.png" },
{ title: "Succulent strawberry", text: "Sorbet", picture: "images/60strawberry.png" },
{ title: "lastitem", text: "test", picture: "images/60strawberry.png" }
];
var dataList = new WinJS.Binding.List(dataArray);
// Create a namespace to make the data publicly
// accessible.
var publicMembers =
{
itemList: dataList
};
WinJS.Namespace.define("DataExample", publicMembers);
})();
本文介绍如何处理ListView在AppBar显示时被遮挡的问题。通过响应AppBar的beforeshow和beforehide事件,动态调整ListView的高度,确保内容可见。通过示例代码展示了解决方案,并解释了其工作原理。
6684

被折叠的 条评论
为什么被折叠?



