多點觸控網站開發

鮑里斯 (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 元素。
  • 用戶端/網頁/畫面座標:發生動作在畫面上的位置。
  • 半徑座標和 rotationAngle:描述接近手指形狀的橢圓形。

支援觸控功能的應用程式

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 Ireland 和其他提供者的畫布型繪圖示範。

繪圖螢幕截圖

Browser Ninja 技術示範為使用 CSS3 轉換和轉換的 Fruit Ninja 本機副本以及畫布:

瀏覽器 Ninja

最佳做法

禁止縮放

預設設定不適用於多點觸控手勢,因為您的滑動和手勢通常與瀏覽器行為 (例如捲動和縮放) 相關聯。

如要停用縮放功能,請使用下列中繼標記設定可視區域,讓使用者無法縮放:

<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 和改良式觸控功能

請記得,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 元素。
  • touchtouch:移動的手指離開 DOM 元素。
  • touchcancel:觸控中斷 (實作特定)。

在每個觸控清單內,受測試的瀏覽器也會提供 touchestargetToucheschangedTouches 觸控清單。不過,沒有任何測試過的瀏覽器都支援 radiusX、radiusY 或 rotationAngle,可用於指定手指輕觸螢幕的形狀。

在觸控移動期間,所有測試裝置都會每秒觸發事件約 60 次。

Android 2.3.3 (Nexus)

在 Nexus One 和 Nexus S 上的 Android Gingerbread 瀏覽器則不支援多點觸控功能。這是已知問題

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. 下載 TongSeng TUIO 應用程式 (適用於 Mac 的 MagicPad) 並啟動伺服器。
  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>

您可能需要啟用外掛程式。

如需使用 magictouch.js 的即時示範,請前往 paulirish.com/demo/multi

我只在使用 Chrome 10 時測試這個方法,但應該可以在其他只會微幅調整的新型瀏覽器上運作。

如果電腦沒有多點觸控輸入,您可以使用其他 TUIO 追蹤器 (例如 reacTIVision) 模擬觸控事件。詳情請參閱 TUIO 專案頁面

請注意,您的手勢可能與作業系統層級的多點觸控手勢相同。在 OS X 中,前往「System Preferences」中的「Trackpad」偏好設定窗格,即可設定整個系統的事件。

隨著行動瀏覽器進一步支援多點觸控功能,我們很高興能看到新的網頁應用程式充分運用這個豐富的 API。