說說iOS中的手勢及觸摸

来源:http://www.cnblogs.com/shouce/archive/2016/04/07/5362061.html
-Advertisement-
Play Games

一、響應鏈 在IOS開發中會遇到各種操作事件,通過程式可以對這些事件做出響應。 首先,當發生事件響應時,必須知道由誰來響應事件。在IOS中,由響應者鏈來對事件進行響應,所有事件響應的類都是UIResponder的子類,響應者鏈是一個由不同對象組成的層次結構,其中的每個對象將依次獲得響應事件消息的機會 ...


一、響應鏈

在IOS開發中會遇到各種操作事件,通過程式可以對這些事件做出響應。

首先,當發生事件響應時,必須知道由誰來響應事件。在IOS中,由響應者鏈來對事件進行響應,所有事件響應的類都是UIResponder的子類,響應者鏈是一個由不同對象組成的層次結構,其中的每個對象將依次獲得響應事件消息的機會。當發生事件時,事件首先被髮送給第一響應者,第一響應者往往是事件發生的視圖,也就是用戶觸摸屏幕的地方。事件將沿著響應者鏈一直向下傳遞,直到被接受並做出處理。一般來說,第一響應者是個視圖對象或者其子類對象,當其被觸摸後事件被交由它處理,如果它不處理,事件就會被傳遞給它的視圖控制器對象viewcontroller(如果存在),然後是它的父視圖(superview)對象(如果存在),以此類推,直到頂層視圖。接下來會沿著頂層視圖(top view)到視窗(UIWindow對象)再到程式(UIApplication對象),如果UIApplication也不響應,那麼還有一個地方可以構建一個全局響應者作為響應鏈的最後一個環節,那就是應用程式的委托,前提是他是UIResponder的子類。如果整個過程都沒有響應這個事件,該事件就被丟棄。一般情況下,在響應者鏈中只要由對象處理事件,事件就停止傳遞。

一個典型的相應路線圖如:

First Responser -- > The Window -- >The Application -- > App Delegate

正常的響應者鏈流程經常被委托(delegation)打斷,一個對象(通常是視圖)可能將響應工作委托給另一個對象來完成(通常是視圖控制器ViewController),這就是為什麼做事件響應時在ViewController中必須實現相應協議來實現事件委托。在iOS中,存在UIResponder類,它定義了響應者對象的所有方法。UIApplication、UIView等類都繼承了UIResponder類,UIWindow和UIKit中的控制項因為繼承了UIView,所以也間接繼承了UIResponder類,這些類的實例都可以當作響應者。

 

管理事件分發

視圖對觸摸事件是否需要作處回應可以通過設置視圖的userInteractionEnabled屬性。預設狀態為YES,如果設置為NO,可以阻止視圖接收和分發觸摸事件。除此之外,當視圖被隱藏(setHidden:YES)或者透明(alpha值為0)也不會收事件。不過這個屬性只對視圖有效,如果想要整個程式都步響應事件,可以調用UIApplication的beginIngnoringInteractionEvents方法來完全停止事件接收和分發。通過endIngnoringInteractionEvents方法來恢復讓程式接收和分發事件。

如果要讓視圖接收多點觸摸,需要設置它的multipleTouchEnabled屬性為YES,預設狀態下這個屬性值為NO,即視圖預設不接收多點觸摸。

 

二、觸摸

iPhone中處理觸摸屏的操作,在3.2之前是主要使用的是由UIResponder提供的如下4種方式:

 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event  //手指觸摸屏幕時報告UITouchPhaseBegan事件

 - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event   //在手指在屏幕上移動時報告UITouchPhaseMoved事件

 - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event   //在手指離開屏幕時報告UITouchPhaseEnded事件

 - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event    //在因接聽電話或其他因素導致取消觸摸時報告UITouchPhaseCancelled事件

屬性:

——UITouch

UITouch對象是一個手指接觸到屏幕併在屏幕上移動或離開屏幕時創建的。它有幾個屬性和實例方法:

phase:屬性,返回一個階段常量,指出觸摸開始、繼續、結束或被取消,是一個枚舉配型,包含了

·UITouchPhaseBegan(觸摸開始)

·UITouchPhaseMoved(接觸點移動)

·UITouchPhaseStationary(接觸點無移動)

·UITouchPhaseEnded(觸摸結束)

·UITouchPhaseCancelled(觸摸取消)

tapCount:屬性,輕按屏幕的次數

timeStamp:屬性,觸摸發生的時間

view:屬性,觸摸始於那個視圖

window:屬性,觸摸始於哪個視窗

lacationInView:方法,觸摸在指定視圖中的當前位置

previousLocationView:方法,觸摸在指定視圖中的前一個位置

——UIEvent

UIEvent對象包含一組相關的UITouch對象,由UITouch對象組成UIEvent對象,可以理解成一個完整的觸摸操作是一個UIEvent,而這一系列完整操作中的每個點就是UITouch(按下、移動、離開)。

UIEvent的作用是提供相關觸摸操作的列表,如果要獲取在屏幕上觸摸的手勢,可以使用該對象,這一些列操作都存儲在Foundation框架中的NSSet對象中。

 

但是這種方式甄別不同的手勢操作實在是麻煩,需要你自己計算做不同的手勢分辨。後來。。。

蘋果就給出了一個比較簡便的方式,就是使用UIGestureRecognizer。

三、UIGestureRecognizer

UIGestureRecognizer基類是一個抽象類,我們主要是使用它的子類(名字包含鏈接,可以點擊跳到ios Developer library,看官方文檔):

UITapGestureRecognizer

UIPinchGestureRecognizer

UIRotationGestureRecognizer

UISwipeGestureRecognizer

UIPanGestureRecognizer

UILongPressGestureRecognizer

從名字上我們就能知道, Tap(點擊)、Pinch(捏合)、Rotation(旋轉)、Swipe(滑動,快速移動,是用於監測滑動的方向的)、Pan (拖移,慢速移動,是用於監測偏移的量的)以及 LongPress(長按)。

舉個例子,可以在viewDidLoad函數裡面添加:

[cpp] view plaincopyprint?

-(void) viewDidLoad  

{  

 [super viewDidLoad];  

 // Do any additional setup after loading the view from its nib.  

 UIPanGestureRecognizer *panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePanFrom:)];  

 [self.view addGestureRecognizer:panRecognizer];//關鍵語句,給self.view添加一個手勢監測;  

 panRecognizer.maximumNumberOfTouches = 1;  

 panRecognizer.delegate = self;  

 [panRecognizer release];  

}  

其它手勢方法類似。

其核心就是設置delegate和在需要手勢監測的view上使用addGestureRecognizer添加指定的手勢監測。

當然要記得在作為delegate的view的頭文件加上<UIGestureRecognizerDelegate>。

不過有些手勢是關聯的,怎麼辦呢?例如 Tap 與 LongPress、Swipe與 Pan,或是 Tap 一次與Tap 兩次。

手勢識別是具有互斥的原則的,比如單擊和雙擊,如果它識別出一種手勢,其後的手勢將不被識別。所以對於關聯手勢,要做特殊處理以幫助程式甄別,應該把當前手勢歸結到哪一類手勢裡面。

比如,單擊和雙擊並存時,如果不做處理,它就只能發送出單擊的消息。為了能夠識別出雙擊手勢,就需要做一個特殊處理邏輯,即先判斷手勢是否是雙擊,在雙擊失效的情況下作為單擊手勢處理。使用

[A requireGestureRecognizerToFail:B]函數,它可以指定當A手勢發生時,即便A已經滿足條件了,也不會立刻觸發,會等到指定的手勢B確定失敗之後才觸發。

[cpp] view plaincopyprint?

- (void)viewDidLoad   

{  

    // 單擊的 Recognizer  

    UITapGestureRecognizer* singleRecognizer;  

    singleRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:selfaction:@selector(SingleTap:)];  

    //點擊的次數  

    singleTapRecognizer.numberOfTapsRequired = 1; // 單擊  

  

    //給self.view添加一個手勢監測;  

  

  [self.view addGestureRecognizer:singleRecognizer];  

  

    

    // 雙擊的 Recognizer  

    UITapGestureRecognizer* double;  

    doubleRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:selfaction:@selector(DoubleTap:)];  

    doubleTapRecognizer.numberOfTapsRequired = 2; // 雙擊  

    //關鍵語句,給self.view添加一個手勢監測;  

    [self.view addGestureRecognizer:doubleRecognizer];  

      

    // 關鍵在這一行,雙擊手勢確定監測失敗才會觸發單擊手勢的相應操作  

    [singleRecognizer requireGestureRecognizerToFail:doubleRecognizer];  

    [singleRecognizer release];  

    [doubleRecognizer release];  

}  

  

-(void)SingleTap:(UITapGestureRecognizer*)recognizer  

{  

//處理單擊操作  

}  

  

-(void)DoubleTap:(UITapGestureRecognizer*)recognizer  

{  

//處理雙擊操作  

}  

四、iphone操作手勢的大概種類

1.點擊(Tap)

點擊作為最常用手勢,用於按下或選擇一個控制項或條目(類似於普通的滑鼠點擊)、

2.拖動(Drag)

拖動用於實現一些頁面的滾動,以及對控制項的移動功能。

3.滑動(Flick)

滑動用於實現頁面的快速滾動和翻頁的功能。

4.橫掃(Swipe)

橫掃手勢用於激活列表項的快捷操作菜單

5.雙擊(Double Tap)

雙擊放大並居中顯示圖片,或恢複原大小(如果當前已經放大)。同時,雙擊能夠激活針對文字編輯菜單。

6.放大(Pinch open)

放大手勢可以實現以下功能:打開訂閱源,打開文章的詳情。在照片查看的時候,放大手勢也可實現放大圖片的功能。

7.縮小(Pinch close)

縮小手勢,可以實現與放大手勢相反且對應的功能的功能:關閉訂閱源退出到首頁,關閉文章退出至索引頁。在照片查看的時候,縮小手勢也可實現縮小圖片的功能。

8.長按(Touch &Hold)

在我的訂閱頁,長按訂閱源將自動進入編輯模式,同時選中手指當前按下的訂閱源。這時可直接拖動訂閱源移動位置。

針對文字長按,將出現放大鏡輔助功能。鬆開後,則出現編輯菜單。

針對圖片長按,將出現編輯菜單。

9.搖晃(Shake)

搖晃手勢,將出現撤銷與重做菜單。主要是針對用戶文本輸入的。

 

五、通過消息響應者鏈找到UIView所在的UIViewController 

@interface UIView (FirstViewController)

 

- (UIViewController *) firstViewController;

- (id) traverseResponderChainForUIViewController;

 

@end

 

@implementation UIView (FirstViewController)

 

- (UIViewController *) firstViewController {

    // convenience function for casting and to "mask" the recursive function

    return (UIViewController *)[self traverseResponderChainForUIViewController];

}

 

- (id) traverseResponderChainForUIViewController {

    id nextResponder = [self nextResponder];

    if ([nextResponder isKindOfClass:[UIViewController class]]) {

        return nextResponder;

    } else if ([nextResponder isKindOfClass:[UIView class]]) {

        return [nextResponder traverseResponderChainForUIViewController];

    } else {

        return nil;

    }

}

六、事件傳遞

當一個子view需要接收點擊事件,其父view也需要接收點擊事件,該如何處理:

按照正常情況下,子類接收點擊事件以後,事件不會主動傳遞到下一個響應者,因此父類便不再接收點擊事件。如果子類不處理點擊事件,則事件會一直傳遞下去,直到UIApplication。

但是我們可以使得子類處理過響應事件後仍將響應這傳遞到下一個響應者。但是我們編寫代碼才能辦到。

子view的代碼如下:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {

// 這裡可以做子view自己想做的事,做完後,事件繼續上傳,就可以讓其父類,甚至父viewcontroller獲取到這個事件了

   [[selfnextResponder]touchesBegan:toucheswithEvent:event];

}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {

  [[selfnextResponder]touchesEnded:toucheswithEvent:event];

}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {

  [[selfnextResponder] touchesCancelled:toucheswithEvent:event];

}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {

  [[selfnextResponder] touchesMoved:toucheswithEvent:event];

}


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 實現目標:年月日三個select 輸入框,以及一個hidden的input,通過js獲取input的值,如果有值切是日期格式,年月日select為input中的時間。否則為空。年預設區間段為1900年到當今年份 本人使用了bootstrap,class請參照bootstrap的相關說明 下麵是htm ...
  • 項目地址 https://github.com/brinley/jSignature demo地址 http://willowsystems.github.io/jSignature/ /demo/ 初始化 getData 獲得canvas上的圖像數據,推薦使用 base30格式,相對於其他格式,存 ...
  • 前言 為了更好理解浮動和position,建議先看看我寫的這篇文章《Html文檔流和文檔對象模型DOM理解》 正文 一、浮動 CSS設計float屬性的主要目的,是為了實現文本繞排圖片的效果。然而,這個屬性居然也成了創建多欄佈局最簡單的方式。 如何浮動一個元素?先設定其寬度width,再增加樣式規則 ...
  • 0.導入框架準備工作 •1. 將AFNetworking3.0+框架程式拖拽進項目 •2. 或使用Cocopod 導入AFNetworking3.0+ •3. 引入 #import "AFNetworking.h" > 1.UI準備工作 A. 定義一個全局的 NSURLSessionDownload ...
  • 轉載請註明出處:http://blog.csdn.net/guolin_blog/article/details/47803149 之前有很多朋友都問過我,在Android系統中怎樣才能實現靜默安裝呢?所謂的靜默安裝,就是不用彈出系統的安裝界面,在不影響用戶任何操作的情況下不知不覺地將程式裝好。雖說 ...
  • 以下問題都是自己在項目中遇到的,解決問題的方法肯定有多種,我所列舉的不一定就是最好的解決辦法。如有問題歡迎大家指正,補充,交流。 解決同時按兩個按鈕進兩個view的問題。[button setExclusiveTouch:YES]; 在6p模擬器上輸出寬度是414,在6p真機上輸出是375是測試機本 ...
  • 代碼: ...
  • 以下是三個IOS開發中最常用的控制項,作為IOS基礎學習教程知識 ,初學者需要瞭解其基本定義和常用設置,以便在開發在熟練運用。 UIButton按鈕 第一、UIButton的定義 UIButton *button=[[UIButton buttonWithType:(UIButtonType); 能夠 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...