UIGestureRecognizer與UIMenuController

UIGestureRecognizer對象會(huì)截取本應(yīng)由視圖處理的觸摸事件。當(dāng)某個(gè)UIGestureRecognizer對象識別出特定的手勢后,就會(huì)向指定的對象發(fā)送指定的消息。
 在為應(yīng)用添加手勢識別功能時(shí),需要針對特定的手勢創(chuàng)建相應(yīng)的UIGestureRecognizer子類對象,而不是直接使用UIGestureRecognizer對象。
 使用UIGestureRecognizer子類對象時(shí),除了要設(shè)置目標(biāo)動(dòng)作對,還要將該子類對象“附著”在某個(gè)視圖上。當(dāng)該子類對象根據(jù)當(dāng)前附著的視圖所發(fā)生的觸摸事件識別出相應(yīng)的手勢時(shí),就會(huì)向指定的目標(biāo)對象發(fā)送指定的動(dòng)作消息。由UIGestureRecognizer對象發(fā)出的動(dòng)作消息都會(huì)遵守以下規(guī)范:

-(void)action:(UIGestureRecognizer*)gestureRecognizer;

UIGestureRecognizer對象在識別手勢時(shí),會(huì)截取本應(yīng)由其附著的視圖自行處理的觸摸事件。附著了UIGestureRecognizer對象的視圖可能不會(huì)收到常規(guī)的UIResponder消息,例如touchesBegan:withEvent:。

UIGestureRecognizer對象會(huì)截取UITouch對象

由于UIGestureRecognizer對象會(huì)通過截取觸摸事件來識別手勢,因此,在UIGestureRecognizer對象識別出手勢之前,UIView會(huì)收到所有UIResponder消息。對于UITapGestureRecognizer來說,在識別出點(diǎn)擊手勢(在屏幕中的一小塊區(qū)域觸摸并迅速抬起手指)之前,UIView會(huì)收到touchesBegan:withEvent:消息;在識別出點(diǎn)擊手勢之后,UITapGestureRecognizer會(huì)自行處理相關(guān)觸摸事件,由這些觸摸事件所引發(fā)的UIResponder消息將不會(huì)再發(fā)送給UIView。直到UITapGestureRecognizer檢測出點(diǎn)擊手勢已經(jīng)結(jié)束,UIView才會(huì)重新收到UIResponder消息(touchesCancelled:withEvent:)。

//延遲touchesBegan的接收
 double  TapRecognizer.delaysTouchesBegan=YES;

如果需要為視圖添加多種手勢,就需要考慮這些手勢之間的關(guān)系。雙擊手勢包含兩次單擊,為了避免UITapGestureRecognizer將雙擊事件分拆為兩個(gè)單擊事件,可以設(shè)置UITapGestureRecognizer在單擊后暫時(shí)不進(jìn)行識別,直到確定不是雙擊手勢后再識別為單擊手勢。

 [tapRecognizer requireGestureRecognizerToFail:doubleTapRecognizer];
UIMenuController

UIMenuController對象可以包含一組UIMenuItem對象(菜單項(xiàng)),并能在現(xiàn)有的視圖上顯示這些UIMenuItem對象。
每個(gè)iOS應(yīng)用只有一個(gè)UIMenuController對象。當(dāng)應(yīng)用要顯示該對象時(shí),要先為它設(shè)置一組UIMenuItem對象,然后設(shè)置顯示位置(矩形區(qū)域),最后將其設(shè)置為可見。
要顯示UIMenuController對象,還要滿足一個(gè)條件:顯示UIMenuController對象的UIView對象必須是當(dāng)前UIWindow對象的第一響應(yīng)對象。
這是因?yàn)樵搶ο笤陲@示前會(huì)枚舉所有的UIMenuItem對象,檢查第一響應(yīng)對象是否實(shí)現(xiàn)了指定的動(dòng)作方法。如果沒有實(shí)現(xiàn)該方法,UIMenuController對象就不會(huì)顯示相應(yīng)的UIMenuItem對象;如果所有UIMenuItem對象的動(dòng)作方法都沒有實(shí)現(xiàn),應(yīng)用就不會(huì)顯示UIMenuController對象。
如果要將某個(gè)自定義的UIView子類對象設(shè)置為第一響應(yīng)對象,就必須覆蓋該對象的canBecomeFirstResponder方法。

-(BOOL)canBecomeFirstResponder
{
    return YES;
}

顯示前會(huì)枚舉所有的UIMenuItem對象,檢查第一響應(yīng)對象是否實(shí)現(xiàn)了指定的動(dòng)作方法。如果沒有實(shí)現(xiàn)該方法,UIMenuController對象就不會(huì)顯示相應(yīng)的UIMenuItem對象;如果所有UIMenuItem對象的動(dòng)作方法都沒有實(shí)現(xiàn),應(yīng)用就不會(huì)顯示UIMenuController對象。
  當(dāng)某個(gè)UIGestureRecognizer子類對象觸發(fā)特定的事件后,其state屬性會(huì)發(fā)生變化。以UILongPressGestureRecognizer對象為例,和上述三種事件相對應(yīng)的state屬性分別為:UIGestureRecognizerStatePossible、UIGestureRecognizerStateBegan和UIGestureRecognizerStateEnded。
  當(dāng)某個(gè)UIGestureRecognizer子類對象的state屬性發(fā)生變化時(shí)(除了切換至UIGestureRecognizerStatePossible的情況),該對象就會(huì)向其目標(biāo)對象發(fā)送指定的動(dòng)作消息。所以當(dāng)某個(gè)長按手勢開始和結(jié)束時(shí),相應(yīng)的UILongPressGestureRecognizer對象都會(huì)向其目標(biāo)對象發(fā)送同一個(gè)消息。和該消息匹配的方法可以通過UIGestureRecognizer對象的state屬性來判斷當(dāng)前的事件類型,然后根據(jù)不同的事件類型執(zhí)行不同的代碼。
  通常情況下,UIGestureRecognizer對象不會(huì)將其處理過的觸摸事件再交給其他對象來處理。一旦某個(gè)UIGestureRecognizer子類對象識別出了相應(yīng)的手勢,就會(huì)“吃掉”所有相關(guān)的觸摸事件,導(dǎo)致其他UIGestureRecognizer對象沒有機(jī)會(huì)再處理這些觸摸事件。對TouchTracker,這種特性會(huì)導(dǎo)致BNRDrawView對象無法處理拖動(dòng)手勢,這是因?yàn)檎麄€(gè)拖動(dòng)手勢都是在長按手勢中發(fā)生的。要解決這個(gè)問題,需要讓UILongPressGestureRecognizer對象和UIPanGestureRecognizer對象能夠同時(shí)識別手勢。
  UIGestureRecognizerDelegate協(xié)議聲明了很多方法,gestureRecognizer: shouldRecognizeSimultaneouslyWithGestureRecognizer:(如下代碼)。當(dāng)某個(gè)UIGestureRecognizer子類對象識別出特定的手勢后,如果發(fā)現(xiàn)其他的UIGestureRecognizer子類對象也識別出了特定的手勢,就會(huì)向其委托對象發(fā)送gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:消息。如果相應(yīng)的方法返回YES,那么當(dāng)前的UIGestureRecognizer子類對象就會(huì)和其他UIGestureRecognizer子類對象共享UITouch對象。

-(BOOL)gestureRecognizer: (UIGestureRecognizer*) gestureRecognizer
shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer*)other
{
    if(gestureRecognizer==self.moveRecognizer)
    {
        return YES;
        
    }
        return NO;
}
//將當(dāng)前手指的位置設(shè)置為初始手勢的位置
[gr setTranslation:CGPointZero inView:self];

現(xiàn)UIPanGestureRecognizer對象的動(dòng)作方法moveLine:。在moveLine:中,要調(diào)用UIPanGestureRecognizer對象的translationInView:方法。該方法會(huì)根據(jù)傳入的UIView對象的坐標(biāo)系,以CGPoint結(jié)構(gòu)的形式返回手指的拖動(dòng)距離。當(dāng)拖動(dòng)手勢開始時(shí),拖動(dòng)距離是0點(diǎn)(x和y都是0)。拖動(dòng)的過程中,拖動(dòng)距離會(huì)不斷發(fā)生變化(將手指移動(dòng)至窗口的最右端,x的值就會(huì)很高。將手指移回手勢的起始位置,拖動(dòng)距離就會(huì)變回0點(diǎn))。
  當(dāng)UIGestureRecognizer對象的cancelsTouchesInView屬性為NO時(shí),這個(gè)對象所依附的UIView對象仍然會(huì)收到相應(yīng)的UIResponder消息,從而有機(jī)會(huì)處理相關(guān)的UITouch對象。

UIMenuController與UIResponderStandardEditActions

如果某個(gè)UIResponder子類需要實(shí)現(xiàn)特定的“編輯”功能,就可以實(shí)現(xiàn)相應(yīng)的方法。以UITextField為例,為了能夠剪切當(dāng)前選中的文字,UITextField實(shí)現(xiàn)了cut:方法。UIResponderStandardEditActions協(xié)議聲明了所有這類“編輯”方法。
  如果某個(gè)UIView子類實(shí)現(xiàn)了UIResponderStandardEditActions協(xié)議中的方法,那么當(dāng)這個(gè)子類對象顯示UIMenuController對象時(shí),就會(huì)出現(xiàn)和這些方法相對應(yīng)的菜單項(xiàng)。這是因?yàn)樵搶ο髸?huì)在顯示前枚舉所有的“編輯”菜單項(xiàng),然后根據(jù)其動(dòng)作消息向視圖發(fā)送canPerformAction:withSender:消息。如果視圖實(shí)現(xiàn)了指定的方法,該消息就會(huì)返回YES,否則返回NO。UIMenuController對象會(huì)根據(jù)canPerformAction:withSender:的返回結(jié)果判斷是否應(yīng)該顯示相應(yīng)的菜單項(xiàng)。

-(BOOL)canPerformAction:(SEL) actionwithSender:(id)sender  
{  
if(action == @selector(copy:)) 
{
  returnNO;
}
 //父類的實(shí)現(xiàn)會(huì)根據(jù)目標(biāo)對象是否實(shí)現(xiàn)了特定的動(dòng)作方法,返回YES或NO 
 return  [super  canPerformAction:action  withSender:sender];
}
再談UIGestureRecognizer

13.8

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容