簡介
智慧型手機和平板電腦等行動裝置通常會採用電容式觸控螢幕,以便擷取使用者手指的互動動作。隨著行動網路不斷演進,應用程式也變得越來越精密,網頁開發人員必須設法處理這些事件。舉例來說,幾乎所有快節奏遊戲都需要玩家同時按下多個按鈕,在觸控螢幕的情況下,這就意味著多點觸控。
Apple 在 iOS 2.0 中推出了觸控事件 API。Android 一直在追上這個實際標準,並縮小差距。最近,W3C 工作小組已開始著手處理這個觸控事件規格。
在本文中,我將深入探討 iOS 和 Android 裝置提供的觸控事件 API,以及支援觸控功能的硬體上的 Chrome 桌面版,並探索您可以建構的應用程式類型、介紹一些最佳做法,以及涵蓋有助於更輕鬆開發支援觸控功能的應用程式實用技巧。
觸控事件
規格說明了三種基本觸控事件,並廣泛實作於行動裝置上:
- touchstart:手指放在 DOM 元素上。
- touchmove:手指沿著 DOM 元素拖曳。
- touchend:手指從 DOM 元素移除。
每個觸控事件都包含三個觸控清單:
- touches:目前在螢幕上所有手指的清單。
- targetTouches:目前 DOM 元素上的手指清單。
- changedTouches:與目前事件有關的手指清單。舉例來說,在觸控事件中,這將是遭移除的手指。
這些清單由包含觸控資訊的物件組成:
- ID:用以在觸控工作階段中識別目前手指的數字。
- target:動作的目標 DOM 元素。
- 用戶端/網頁/畫面座標:動作在畫面上發生的位置。
- 半徑座標和旋轉角度:描述大致呈手指形狀的橢圓形。
支援觸控的應用程式
touchstart、touchmove 和 touchend 事件提供足夠的功能集,可支援幾乎任何類型的觸控互動,包括雙指撥動縮放、旋轉等所有常見的多點觸控手勢。
這個程式碼片段可讓您使用單指觸控方式拖曳 DOM 元素:
var obj = document.getElementById('id');
obj.addEventListener('touchmove', function(event) {
// If there's exactly one finger inside this element
if (event.targetTouches.length == 1) {
var touch = event.targetTouches[0];
// Place element where the finger is
obj.style.left = touch.pageX + 'px';
obj.style.top = touch.pageY + 'px';
}
}, false);
以下是範例,會顯示螢幕上目前的所有觸控動作。這麼做有助於您瞭解裝置的回應速度。
// Setup canvas and expose context via ctx variable
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 轉換和轉場效果,以及畫布模擬的《水果忍者》克隆遊戲:
最佳做法
禁止縮放
由於滑動和手勢經常與瀏覽器行為 (例如捲動和縮放) 相關聯,因此預設設定無法有效支援多點觸控。
如要停用縮放功能,請使用下列中繼標記,設定可視區域,以便使用者無法縮放:
<meta name="viewport"
content="width=device-width, initial-scale=1.0, user-scalable=no>
如要進一步瞭解如何設定檢視區,請參閱這篇行動版 HTML5 文章。
禁止捲動
部分行動裝置具有觸控移動的預設行為,例如經典的 iOS 超捲效果,會在捲動超出內容邊界時,導致檢視區塊彈回。這在許多多點觸控應用程式中會造成混淆,而且可以輕鬆停用:
document.body.addEventListener('touchmove', function(event) {
event.preventDefault();
}, false);
謹慎轉譯
如果您要編寫涉及複雜多指手勢的多點觸控應用程式,請小心處理觸控事件,因為您必須一次處理多個事件。請參考上一節中用於繪製畫面上所有觸控動作的範例。一有觸控輸入,您就可以開始繪圖:
canvas.addEventListener('touchmove', function(event) {
renderTouches(event.touches);
}, false);
但這種技巧無法隨著螢幕上手指的數量而調整。您可以改為追蹤所有手指,並在迴圈中算繪,以獲得更出色的效能:
var touches = []
canvas.addEventListener('touchmove', function(event) {
touches = event.touches;
}, false);
// Setup a 60fps timer
timer = setInterval(function() {
renderTouches(touches);
}, 15);
善用 targetTouches 和 changedTouches
請注意,event.touches 是 所有與螢幕接觸的手指陣列,而非 DOM 元素目標上的手指。您可能會發現改用 event.targetTouches 或 event.changedTouches 是更實用的做法。
最後,由於你開發的是適合行動裝置的應用程式,因此請留意 Eric Bidelman 文章中的一般行動廣告最佳做法,以及這篇 W3C 文件。
確認裝置支援情形
但很遺憾,觸控事件實作項目的完整性和品質差異很大。我編寫的診斷指令碼會顯示觸控 API 實作的一些基本資訊 (包括支援的事件與觸控移動啟動解析度)。我在 Nexus One 和 Nexus S 硬體上測試 Android 2.3.3、Xoom 上的 Android 3.0.1,以及在 iPad 和 iPhone 上測試 iOS 4.2。
簡而言之,所有測試過的瀏覽器都支援 touchstart、touchend 和 touchmove 事件。
規格提供三個額外的觸控事件,但經過測試的瀏覽器都未支援這些事件:
- touchenter:手指移動進入 DOM 元素。
- touchleave:手指移動離開 DOM 元素。
- touchcancel:觸控動作中斷 (實作方式視情況而定)。
在每個觸控清單中,測試的瀏覽器也會提供 touches、targetTouches 和 changedTouches 觸控清單。不過,在測試的瀏覽器中,沒有任何瀏覽器支援 radiusX、radiusY 或 rotationAngle,這些屬性可指定手指觸碰螢幕的形狀。
在觸控移動期間,所有測試裝置都會以約 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 裝置完整支援多點觸控功能,可支援以少數手指追蹤,並透過瀏覽器提供回應迅速的觸控體驗。
開發人員工具
在行動裝置開發作業中,通常比較容易在電腦上開始製作原型,然後在您要支援的裝置上處理行動裝置專屬部分。多點觸控功能是在電腦上難以測試的功能之一,因為大多數電腦都沒有觸控輸入功能。
必須在行動裝置上進行測試,可能會延長開發週期,因為您所做的每個變更都必須推送至伺服器,然後載入裝置上。然後,一旦執行應用程式,您就無法對應用程式進行偵錯,因為平板電腦和智慧型手機缺乏網路開發人員工具。
解決這個問題的方法是在開發機器上模擬觸控事件。針對單一觸控動作,您可以根據滑鼠事件模擬觸控事件。如果您有支援觸控輸入的裝置 (例如新款 Apple MacBook),就可以模擬多點觸控事件。
單點觸控事件
如要在電腦上模擬單一觸控事件,Chrome 提供開發人員工具中的觸控事件模擬功能。開啟「開發人員工具」,然後依序選取「設定」齒輪圖示、「覆寫」或「模擬」,然後開啟「模擬觸控事件」。
針對其他瀏覽器,不妨試試 Phantom Limb,這個程式會模擬網頁上的觸控事件,並賦予巨大的啟動技術。
此外,還有 Touchable jQuery 外掛程式,可在各平台上統一觸控和滑鼠事件。
多點觸控事件
如要讓多點觸控網頁應用程式在瀏覽器中運作 (例如 Apple MacBook 或 MagicPad),我們建立了 MagicTouch.js polyfill。這項功能會擷取觸控板的觸控事件,並將其轉換為與標準相容的觸控事件。
- 下載 npTuioClient NPAPI 外掛程式,然後安裝至 ~/Library/Internet Plug-Ins/。
- 下載適用於 Mac 的 TongSeng TUIO 應用程式,然後啟動伺服器。
- 下載 MagicTouch.js,這是一個 JavaScript 程式庫,可根據 npTuioClient 回呼模擬與規格相容的觸控事件。
- 在應用程式中加入 magictouch.js 指令碼和 npTuioClient 外掛程式,如下所示:
<head>
...
<script src="/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>
您可能需要啟用該外掛程式。
你可以在 paulirish.com/demo/multi 中找到使用魔術 touch.js 的現場示範影片:
我只在 Chrome 10 上測試這個方法,但應該也適用於其他新式瀏覽器,只需稍微調整即可。
如果電腦沒有多點觸控輸入功能,您可以使用其他 TUIO 追蹤工具 (例如 reacTIVision) 模擬觸控事件。詳情請參閱 TUIO 專案頁面。
請注意,您的手勢可能與 OS 層級的多點觸控手勢相同。在 OS X 上,您可以前往「系統偏好設定」中的「觸控板」偏好設定窗格,設定整個系統的事件。
隨著跨行動瀏覽器的多點觸控功能越來越多,我很高興看到新的網頁應用程式能充分運用這個豐富的 API。