標籤:
前言
如果我們允許使用者在頁面上用類似案頭瀏覽器滑鼠手勢的方式來控制WEB APP,這個頁面上肯定是有很多可點擊地區的,如果使用者觸摸到了那些可點擊地區怎麼辦呢??
諸如智能手機和平板電腦一類的行動裝置通常會有一個電容式觸控螢幕(capacitive touch-sensitive screen),以捕捉使用者的手指所做的互動。隨著移動網路的發展,其能夠支援越來越複雜的應用,web開發人員需要一種方法來處理這些事件。例如,幾乎所 有的快節奏遊戲都需要玩家一次按下多個按鈕,這種方式,在觸控螢幕情況下,意味著多點觸摸。
Apple在iOS 2.0中引入了觸摸事件API,Android正迎頭趕上這一事實標準,縮小差距。最近一個W3C工作群組正合力制定這一觸摸事件規範。
在本文中,我會深入研究iOS和Android裝置提供的觸摸事件API,探索一下可以構建哪些類型的應用,給出一些最佳做法,並論及一些使得可觸控應用(touch-enabled application)的開發變得更加容易的有用技術。
觸摸事件
三種在規範中列出並獲得跨行動裝置廣泛實現的基本觸摸事件:
1. touchstart :手指放在一個DOM元素上。
2. touchmove :手指拖曳一個DOM元素。
3. touchend :手指從一個DOM元素上移開。
每個觸摸事件都包括了三個觸摸列表:
1. touches :當前位於螢幕上的所有手指的一個列表。
2. targetTouches :位於當前DOM元素上的手指的一個列表。
3. changedTouches :涉及當前事件的手指的一個列表。
例如,在一個touchend事件中,這就會是移開的手指。
這些列表由包含了觸摸資訊的對象組成:
1. identifier :一個數值,唯一標識觸摸會話(touch session)中的當前手指。
2. target :DOM元素,是動作所針對的目標。
3. 客戶/頁面/螢幕座標 :動作在螢幕上發生的位置。
4. 半徑座標和 rotationAngle :畫出大約相當於手指形狀的橢圓形。
可觸控應用
touchstart、touchmove和touchend事件提供了一組足夠豐富的功能來支援幾乎是任何類型的基於觸摸的互動——其中包括常見的多點觸摸手勢,比如說捏縮放、旋轉等待。
下面的這段代碼讓你使用單指觸摸來四處拖曳一個DOM元素:
var obj = document.getElementById(‘id‘);
obj.addEventListener(‘touchmove‘, function(event) {
// 如果這個元素的位置內只有一個手指的話
if (event.targetTouches.length == 1) {
var touch = event.targetTouches[0];
// 把元素放在手指所在的位置
obj.style.left = touch.pageX + ‘px‘;
obj.style.top = touch.pageY + ‘px‘;
}
}, false);
下面是一個樣本,該例子顯示了螢幕上當前所有的觸點,它的作用就是用來感受一下裝置的響應性。
// 設定畫布並通過ctx變數來暴露上下文
canvas.addEventListener(‘touchmove‘, function(event) {
for (var i = 0; i < event.touches.length; i++) {
var touch = event.touches[i];
ctx.beginPath();
ctx.arc(touch.pageX, touch.pageY, 20, 0, 2*Math.PI, true);
ctx.fill();
ctx.stroke();
}
}, false);
示範
到處都有著許多有意思的多點觸摸示範,比如說這個由Paul Irish和其他人實現的基於畫布的繪畫示範 。
還有Browser Ninja ,一個技術示範 , 是一個使用了CSS3的轉換、過渡和畫布的Fruit Ninja複製。
最佳做法
阻止縮放
預設的多點觸摸設定不是特別的好用,因為你的滑動和手勢往往與瀏覽器的行為有關聯,比如說滾動和縮放。
要禁用縮放功能的話,使用下面的元標記設定你的視圖區(viewport),這樣其對於使用者來說就是不可伸縮的了:
content="width=device-width, initial-scale=1.0, user-scalable=no">
看看這篇關於移動HTML 5 的文章,瞭解更多關於視圖區設定的資訊。
阻止滾動
一些行動裝置有預設的touchmove行為,比如說經典的iOS overscroll效果,當滾動超出了內容的界限時就引發視圖反彈。這種做法在許多多點觸控應用中會帶來混亂,但要禁用它很容易。
document.body.addEventListener(‘touchmove‘, function(event) {
event.preventDefault();
}, false);
細心渲染
如果你正在編寫的多點觸控應用涉及了複雜的多指手勢的話,要小心地考慮如何響應觸摸事件,因為一次要處理這麼多的事情。考慮一下前面一節中的在螢幕上畫出所有觸點的例子,你可以在有觸摸輸入的時候就立刻進行繪製:
canvas.addEventListener(‘touchmove‘, function(event) {
renderTouches(event.touches);
},
不過這一技術並不是要隨著螢幕上的手指個數的增多而擴充,替代做法是,可以跟蹤所有的手指,然後在一個迴圈中做渲染,這樣可獲得更好的效能:
var touches = []
canvas.addEventListener(‘touchmove‘, function(event) {
touches = event.touches;
}, false);
// 設定一個每秒60幀的定時器
timer = setInterval(function() {
renderTouches(touches);
}, 15);
提示 :setInterval不太適合於動畫,因為它沒有考慮 到瀏覽器自己的渲染迴圈。現代的案頭瀏覽器提供了requestAnimationFrame這一函數,基於效能和電池工作時間原因,這是一個更好的選 擇。一但瀏覽器提供了對該函數的支援,那將是首選的處理事情的方式。
使用targetTouches和changedTouches
要記住的一點是,event.touches是與螢幕接觸的所有手指的一個數組,而不僅是位於目標DOM元素上的那些。你可能會發現使用 event.targetTouches和event.changedTouches來代替event.touches更有用一些。
最後一點,因為你是在為行動裝置做開發,因此你應該要留心移動的最佳做法,這些在Eric Bidelman的文章 中有論及,以及要瞭解這一W3C文檔 。
裝置支援
遺憾的是,觸摸事件的實現在完備性和品質方面的差別很大。我編寫了一個診斷指令碼來顯示一些關於觸摸API實現的基本資料,其中包括哪些事件是支援 的,以及 touchmove事件觸發的解決方案。我在Nexus One和Nexus S硬體上測試了Android 2.3.3,在Xoom上測試了Android 3.0.1,以及在iPad和iPhone上測試了iOS 4.2。
簡而言之,所有被測試的瀏覽器都支援touchstart、touchend和touchmove事件。
規範提供了額外的三個觸摸事件,但被測試的瀏覽器沒有支援它們:
1. touchenter :移動的手指進入一個DOM元素。
2. toucheleave :移動手指離開一個DOM元素。
3. touchcancel :觸摸被中斷(實現規範)。
被測試的瀏覽器還在每個觸摸列表內部都提供了touches、targetTouches和changedTouches列表。不過,被測試的瀏 覽器沒有支援 radiusX、radiusY或是rotationAngle屬性,這些屬性指明觸控螢幕幕的手指的形狀。在一次touchmove期間,事件大約一秒鐘 觸發60次,所有的被測試裝置都是這樣。
Android 2.3.3 (Nexus)
Android的Gingerbread瀏覽器(在Nexus One和Nexus S上測試)不支援多點觸摸,這是一個已知的問題 。
Android 3.0.1 (Xoom)
Xoom的瀏覽器對多點觸摸有一個基本的支援,不過只能是在單個的DOM元素上起作用。瀏覽器不能正確響應同時發生在不同DOM元素上的兩處觸摸,換句話說,下面的代碼會對兩個同時發生的觸摸的給出反應:
obj1.addEventListener(‘touchmove‘, function(event) {
for (var i = 0; i < event.targetTouches; i++) {
var touch = event.targetTouches[i];
console.log(‘touched ‘ + touch.identifier);
}
}, false);
但下面的代碼則不會:
var objs = [obj1, obj2];
for (var i = 0; i < objs.length; i++) {
var obj = objs[i];
obj.addEventListener(‘touchmove‘, function(event) {
if (event.targetTouches.length == 1) {
console.log(‘touched ‘ + event.targetTouches[0].identifier);
}
}, false);
}
iOS 4.x (iPad, iPhone)
iOS裝置完全支援多點觸摸,能夠跟蹤多個手指,並在瀏覽器中提供一個非常敏感的觸摸體驗。
開發人員工具
在移動開發中,一種較為容易的做法是,先在案頭上開始原型設計,然後再在打算要支援的裝置上處理移動特有的部分。多點觸摸正是難以在PC上進行測試的那些功能之一,因為大部分的PC都沒有觸摸輸入。
不得不在行動裝置上進行的測試有可能會拉長你的開發週期,因為你所做的每項改變都需要提交代碼到伺服器上,接著再載入到裝置上。然後,一旦運行後,對應用也就沒有太多的調試了,因為平板電腦和智能手機都很缺乏web開發人員所用的工具。
這個問題的一個解決方案是在開發機器上類比觸發事件。對於單點觸摸,觸摸事件可以基於滑鼠事件來類比。如果你有觸摸輸入裝置的話,比如說現代的App MacBook,那麼多點觸摸也可以被類比。
單點觸摸事件
如果你想在案頭上類比單點觸摸事件的話,試一下Phantom Limb ,該程式在網頁上類比觸摸事件並提供一隻巨手來引導。
另外還有Touchable 這一jQuery外掛程式,該外掛程式跨平台地統一了觸摸和滑鼠事件。
多點觸摸事件
為了能夠讓你的多點觸摸web應用在你的瀏覽器或是多點觸摸控板(比如說Apple MacBook或是MagicPad)上起作用,我建立了這一個MagicTouch.js填充工具 ,其捕捉來自觸控板的觸摸事件,然後把它們轉換成標準相容的觸摸事件。
1. 下載npTuioClient NPAPI外掛程式 並把它安裝到~/Library/Internet Plug-Ins/目錄下。
2. 下載這一Mac MagicPad的TongSeng TUIO應用 並啟動這一伺服器。
3. 下載MagicTouch.js 這一javascript庫來基於npTuioClient回調類比規範相容的觸摸事件。
4. 以如下方式把magictouch.js指令碼和npTuioClient外掛程式包含到你的應用中:
< head>
...
< script src="/path/to/magictouch.js" kesrc="/path/to/magictouch.js">< /script>
< /head>
< body>
...
< object id="tuio" type="application/x-tuio" style="width: 0px; height: 0px;">
Touch input plugin failed to load!
< /object>
< /body>
我只在Chrome 10上測試了這一方法,不過只要稍做調整它應該能夠在其他的現代瀏覽器上工作。
如果你的電腦沒有多點觸摸輸入的話,你可以使用其他的TUIO跟蹤器,比如說reacTIVision 來類比觸摸事件。欲瞭解更多資訊,請參閱TUIO項目頁面 。
需要注意的一點是,你的手勢可以是和OS層面的多點觸摸手勢相同的。在OS X上,你可以通過進入System Preferences中的Trackpad偏好設定版面來配置系統範圍的事件。
隨著多點觸摸功能逐漸得到跨行動瀏覽器的的廣泛支援,我非常高興地看到新的web應用充分利用了這一豐富的API。
移動互連網終端的touch事件,touchstart, touchend, touchmove