多點觸控網站開發

Boris Smus
Boris Smus

簡介

智慧型手機和平板電腦等行動裝置通常會採用電容式觸控螢幕,以便擷取使用者手指的互動動作。隨著行動網路不斷演進,應用程式也變得越來越精密,網頁開發人員必須設法處理這些事件。舉例來說,幾乎所有快節奏遊戲都需要玩家同時按下多個按鈕,在觸控螢幕的情況下,這就意味著多點觸控。

Apple 在 iOS 2.0 中推出了觸控事件 API。Android 一直在追上這個實際標準,並縮小差距。最近,W3C 工作小組已開始著手處理這個觸控事件規格

在本文中,我將深入探討 iOS 和 Android 裝置提供的觸控事件 API,以及支援觸控功能的硬體上的 Chrome 桌面版,並探索您可以建構的應用程式類型、介紹一些最佳做法,以及涵蓋有助於更輕鬆開發支援觸控功能的應用程式實用技巧。

觸控事件

規格說明了三種基本觸控事件,並廣泛實作於行動裝置上:

  • touchstart:手指放在 DOM 元素上。
  • touchmove:手指沿著 DOM 元素拖曳。
  • touchend:手指從 DOM 元素移除。

每個觸控事件都包含三個觸控清單:

  • touches:目前在螢幕上所有手指的清單。
  • targetTouches:目前 DOM 元素上的手指清單。
  • changedTouches:與目前事件有關的手指清單。舉例來說,在觸控事件中,這將是遭移除的手指。

這些清單由包含觸控資訊的物件組成:

  • ID:用以在觸控工作階段中識別目前手指的數字。
  • target:動作的目標 DOM 元素。
  • 用戶端/網頁/畫面座標:動作在畫面上發生的位置。
  • 半徑座標和旋轉角度:描述大致呈手指形狀的橢圓形。

支援觸控的應用程式

touchstarttouchmovetouchend 事件提供足夠的功能集,可支援幾乎任何類型的觸控互動,包括雙指撥動縮放、旋轉等所有常見的多點觸控手勢。

這個程式碼片段可讓您使用單指觸控方式拖曳 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。

簡而言之,所有測試過的瀏覽器都支援 touchstarttouchendtouchmove 事件。

規格提供三個額外的觸控事件,但經過測試的瀏覽器都未支援這些事件:

  • touchenter:手指移動進入 DOM 元素。
  • touchleave:手指移動離開 DOM 元素。
  • touchcancel:觸控動作中斷 (實作方式視情況而定)。

在每個觸控清單中,測試的瀏覽器也會提供 touchestargetToucheschangedTouches 觸控清單。不過,在測試的瀏覽器中,沒有任何瀏覽器支援 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。這項功能會擷取觸控板的觸控事件,並將其轉換為與標準相容的觸控事件。

  1. 下載 npTuioClient NPAPI 外掛程式,然後安裝至 ~/Library/Internet Plug-Ins/。
  2. 下載適用於 Mac 的 TongSeng TUIO 應用程式,然後啟動伺服器。
  3. 下載 MagicTouch.js,這是一個 JavaScript 程式庫,可根據 npTuioClient 回呼模擬與規格相容的觸控事件。
  4. 在應用程式中加入 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。