Xamarin.iOS 中的觸控事件和手勢
請務必瞭解 iOS 應用程式中的觸控事件和觸控 API,因為它們是與裝置的所有實體互動的核心。 所有觸控互動都牽涉到 UITouch
物件。 在本文中,我們將瞭解如何使用 UITouch
類別及其 API 來支援觸控。 稍後,我們將擴充我們的知識,以瞭解如何支持手勢。
啟用觸控
中的 UIKit
控件 – 從 UIControl 分類的子類別 – 會相依於用戶互動,因此他們有內建 UIKit 的手勢,因此不需要啟用 Touch。 它已經啟用。
不過,中的 UIKit
許多檢視預設並未啟用觸控功能。 有兩種方式可以在控件上啟用觸控。 第一種方式是在 iOS 設計工具的 Property Pad 中核取 [已啟用使用者互動] 複選框,如下列螢幕快照所示:
我們也可以使用控制器,在類別上UIView
將 UserInteractionEnabled
屬性設定為 true。 如果在程式代碼中建立UI,則需要此專案。
下列程式代碼列是範例:
imgTouchMe.UserInteractionEnabled = true;
觸控事件
當使用者觸碰螢幕、移動手指或移除手指時,會發生三個階段的觸控。 這些方法定義於 中 UIResponder
,這是UIView的基類。 iOS 會覆寫 上的 UIView
相關聯方法,以及 UIViewController
用來處理觸控的 :
TouchesBegan
– 第一次觸碰螢幕時,就會呼叫此專案。TouchesMoved
– 當用戶在螢幕上滑動手指時,觸控的位置會變更時,就會呼叫此專案。TouchesEnded
或TouchesCancelled
–TouchesEnded
當使用者的手指從螢幕外抬起時呼叫。TouchesCancelled
如果 iOS 取消觸控,就會呼叫 – 例如,如果使用者將手指從按鈕滑開以取消按下。
觸控事件會透過UIViews堆疊遞歸向下移動,以檢查觸控事件是否位於檢視物件的界限內。 這通常稱為 點擊測試。 它們會先在最UIView
UIViewController
上層或上層呼叫,然後在檢視階層中的 和 UIView
UIViewControllers
下方呼叫它們。
UITouch
每次使用者觸碰畫面時,都會建立物件。 UITouch
物件包含觸控的相關數據,例如觸控發生時、發生的位置、觸控是否為撥動等。觸控事件會傳遞 touchs 屬性 – NSSet
包含一或多個觸控。 我們可以使用這個屬性來取得觸控的參考,並判斷應用程式的回應。
覆寫其中一個觸控事件的類別應該先呼叫基底實作,然後取得 UITouch
與事件相關聯的物件。 若要取得第一個觸控的參考,請呼叫 AnyObject
屬性,並將它轉換成 , UITouch
如下列範例所示:
public override void TouchesBegan (NSSet touches, UIEvent evt)
{
base.TouchesBegan (touches, evt);
UITouch touch = touches.AnyObject as UITouch;
if (touch != null)
{
//code here to handle touch
}
}
iOS 會自動辨識螢幕上連續的快速觸控,並將全部收集為單 UITouch
一物件中的一個點選。 這可讓您像檢查 TapCount
屬性一樣簡單地點選一次,如下列程式代碼所示:
public override void TouchesBegan (NSSet touches, UIEvent evt)
{
base.TouchesBegan (touches, evt);
UITouch touch = touches.AnyObject as UITouch;
if (touch != null)
{
if (touch.TapCount == 2)
{
// do something with the double touch.
}
}
}
多點觸控
控制件上預設不會啟用多點觸控。 您可以在 iOS 設計工具中開啟多點觸控,如下列螢幕快照所示:
您也可以藉由設定 MultipleTouchEnabled
屬性,以程式設計方式設定多點觸控,如下列程式代碼行所示:
imgTouchMe.MultipleTouchEnabled = true;
若要判斷觸碰螢幕的手指數目,請使用 Count
屬性上的 UITouch
屬性:
public override void TouchesBegan (NSSet touches, UIEvent evt)
{
base.TouchesBegan (touches, evt);
lblNumberOfFingers.Text = "Number of fingers: " + touches.Count.ToString();
}
判斷觸控位置
方法 UITouch.LocationInView
會傳回 CGPoint 物件,該物件會保留指定檢視內的觸控座標。 此外,我們可以藉由呼叫 方法來 Frame.Contains
測試該位置是否在控件內。 下列代碼段顯示下列範例:
if (this.imgTouchMe.Frame.Contains (touch.LocationInView (this.View)))
{
// the touch event happened inside the UIView imgTouchMe.
}
既然我們已經瞭解 iOS 中的觸控事件,讓我們來了解手勢辨識器。
手勢辨識器
手勢辨識器可以大幅簡化和減少在應用程式中支援觸控的程序設計工作。 iOS 手勢辨識器會將一系列觸控事件匯總成單一觸控事件。
Xamarin.iOS 提供 類別 UIGestureRecognizer
作為下列內建手勢辨識器的基類:
- UITapGestureRecognizer – 這是針對一或多個點選。
- UIPinchGestureRecognizer – 捏合和分散手指。
- UIPanGestureRecognizer – 移動瀏覽或拖曳。
- UISwipeGestureRecognizer – 以任何方向撥動。
- UIRotationGestureRecognizer – 順時針或逆時針移動旋轉兩根手指。
- UILongPressGestureRecognizer – 按住,有時稱為長按或長按。
使用手勢辨識器的基本模式如下:
- 具現化手勢辨識器 – 首先,具現化
UIGestureRecognizer
子類別。 具現化的物件將會由檢視相關聯,而且會在處置檢視時進行垃圾收集。 不需要將此檢視建立為類別層級變數。 - 設定任何手勢設定 – 下一個步驟是設定手勢辨識器。 如需可設定來控制實例行為
UIGestureRecognizer
的屬性清單,請參閱 XamarinUIGestureRecognizer
的檔及其子類別。 - 設定目標 – 由於其 Objective-C 傳統,Xamarin.iOS 不會在手勢辨識器符合手勢時引發事件。
UIGestureRecognizer
具有方法 –AddTarget
可以接受匿名委派或 Objective-C 具有程式碼的選取器,以在手勢辨識器進行比對時執行。 - 啟用手勢辨識器 – 就像觸控事件一樣,只有在啟用觸控互動時,才會辨識手勢。
- 將手勢辨識器新增至檢視 – 最後一個步驟是呼叫
View.AddGestureRecognizer
,並將手勢辨識器對象傳遞至檢視。
如需如何在程式代碼中實作它們的詳細資訊, 請參閱手勢辨識器範例 。
呼叫手勢的目標時,會傳遞所發生手勢的參考。 這可讓手勢目標取得所發生手勢的相關信息。 可用的資訊範圍取決於所使用的手勢辨識器類型。 如需每個 UIGestureRecognizer
子類別可用數據的相關信息,請參閱 Xamarin 的檔。
請務必記住,一旦將手勢辨識器新增至檢視,檢視(及其下方的任何檢視)將不會收到任何觸控事件。 若要使用手勢同時允許觸控事件, CancelsTouchesInView
屬性必須設定為 false,如下列程式代碼所示:
_tapGesture.Recognizer.CancelsTouchesInView = false;
每個 UIGestureRecognizer
都有 State 屬性,提供手勢辨識器狀態的重要資訊。 每次這個屬性的值變更時,iOS 都會呼叫訂閱方法,給予它更新。 如果自定義手勢辨識器永遠不會更新 State 屬性,則永遠不會呼叫訂閱者,轉譯手勢辨識器無用。
手勢可以摘要為兩種類型之一:
- 離散 – 這些手勢只會在第一次辨識時引發。
- 連續 – 只要辨識這些手勢,這些手勢就會繼續引發。
手勢辨識器存在於下列其中一種狀態:
- 可能 – 這是所有手勢辨識器的初始狀態。 這是 State 屬性的預設值。
- 開始 – 第一次辨識連續手勢時,狀態會設定為 [開始]。 這可讓訂閱區分手勢辨識的開始時間,以及何時變更。
- 已變更 – 連續手勢開始,但尚未完成之後,只要它仍在手勢的預期參數內,每次觸控移動或變更時,狀態就會設定為 [已變更]。
- 已取消 – 如果辨識器從 [開始] 變成 [已變更],然後觸控會以不再符合手勢模式的方式變更,就會設定此狀態。
- 已辨識 – 當筆勢辨識器符合一組觸控時,將會設定狀態,並通知訂閱者手勢已完成。
- 結束 – 這是已辨識狀態的別名。
- 失敗 – 當手勢辨識器無法再符合正在接聽的觸控時,狀態會變更為 [失敗]。
Xamarin.iOS 代表列舉中的 UIGestureRecognizerState
這些值。
使用多個手勢
根據預設,iOS 不允許默認手勢同時執行。 相反地,每個手勢辨識器都會以不具決定性的順序接收觸控事件。 下列代碼段說明如何讓手勢辨識器同時執行:
gesture.ShouldRecognizeSimultaneously += (UIGestureRecognizer r) => { return true; };
您也可以停用 iOS 中的手勢。 有兩個委派屬性可讓手勢辨識器檢查應用程式的狀態和目前的觸控事件,以決定應該如何及是否辨識手勢。 這兩個事件為:
- ShouldReceiveTouch – 此委派會在手勢辨識器通過觸控事件之前立即呼叫,並提供檢查觸控的機會,並決定手勢辨識器將處理哪些觸控。
- ShouldBegin – 當辨識器嘗試將狀態從 [可能] 變更為其他狀態時,就會呼叫此動作。 傳回 false 會強制將手勢辨識器的狀態變更為 [失敗]。
您可以使用強型 UIGestureRecognizerDelegate
別、弱式委派或透過事件處理程式語法系結來覆寫這些方法,如下列代碼段所示:
gesture.ShouldReceiveTouch += (UIGestureRecognizer r, UITouch t) => { return true; };
最後,可以將手勢辨識器排入佇列,以便在另一個手勢辨識器失敗時才會成功。 例如,單一點選手勢辨識器只有在雙擊手勢辨識器失敗時才會成功。 下列代碼段提供下列範例:
singleTapGesture.RequireGestureRecognizerToFail(doubleTapGesture);
建立自定義手勢
雖然 iOS 提供一些預設手勢辨識器,但在某些情況下可能需要建立自定義手勢辨識器。 建立自定義手勢辨識器牽涉到下列步驟:
- 子類別
UIGestureRecognizer
。 - 覆寫適當的觸控事件方法。
- 透過基類的 State 屬性來反升辨識狀態。
在 iOS 中使用觸控逐步解說將涵蓋此案例的實際範例。