iOS手勢 規避同一界面上不同子界面同時響應多個手勢


最近在項目中遇到這樣一個有關iOS手勢的問題,首先需求描述如下:在一個CollectionView中,要求長按不同的cell,產生一個cell的snapshot,此時可拖拽這個snapshot再進行后續的操作(如拖到view的某個位置出發一個事件)”。需求本身並不復雜,但要求每次只能有一個cell響應長按手勢,不允許同時有兩個或以上的cell響應長按手勢。

我們知道UIGestureRecognizer有很多回調和方法可以兼容同一個View上的多種手勢,網上相關的教程也很多,比如:

http://coder.aqualuna.me/2011/07/uigesturerecognizer.html

也有這種很全面的流水式教程:

http://blog.csdn.net/namehzf/article/details/7424882

但是都沒有解決我的問題的方案,因為我研究的是多個subview上的手勢共存問題,不是單個view上不同手勢共存問題。於是求人不如求自己,自己動手解決吧。(為此我做了個簡化的demo放在這里https://github.com/pigpigdaddy/LongPressSingleDemo,供讀者下載斧正)

思路有兩條:

1,將長按手勢加在collectionView上,通過手勢在collectionView上的位置point,獲取此位置的cell(如果有)。優勢:代碼量少,邏輯簡單。劣勢:兩個cell同時長按時,任何一個長按操作都無法識別!

相關代碼:

1 - (void)longPressAction:(UILongPressGestureRecognizer *)ges
2 {
3     if (ges.state == UIGestureRecognizerStateBegan) {
4         CGPoint point = [ges locationInView:self.collectionView];
5         NSIndexPath *indexPath = [self.collectionView indexPathForItemAtPoint:point];
6         NSLog(@"%@==%d==%d",indexPath, indexPath.section, indexPath.row);
7     }
8 }

既然思路1無法實現我的需求,那么我就不就此展開討論,demo代碼中也沒有體現,不過這種思路或許可以適用於其它需求。

2,將長按手勢加在collectionViewCell上,長按響應后,以delegate回調的形式,將所長按cell的location、cell的index等相關屬性上傳到上層,再進行相關后續操作。優勢:可以同時響應一個或者多個cell的長按。劣勢:多個cell同時響應,無法滿足我項目的需求。於是,如何解決呢?這才是這篇文章的關鍵。

UIGestureRecognizer的回調中,有一個最基本的:

 1 - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
 2 {
 3     return YES;
4 }

默認返回YES。那么,如果我在當前cell響應了長按事件后,將這里設置為NO,那么接下來的cell就不在響應長按事件了。另外,當前cell的長按結束后,再將這里設置為YES,后續的cell就又能正常響應自己的長按事件了。

於是,我創建了一個單例,專門用於控制全局的長按事件,之所以做成單例,而不在cell的上層view來記錄長按狀態,因為考慮到項目之間的通用性,以后項目如果需要這樣的需求,可以直接引用這個單例類。

OK,下面是我的單例的接口文件:

 1 //
 2 //  LongPressControl.h
 3 //  Classroom
 4 //
 5 //  Created by pigpigdaddy on 14-3-24.
 6 //  Copyright (c) 2014年 pigpigdaddy. All rights reserved.
 7 //
 8 //  某些界面上可能會有多個子界面,這些子界面都有自己的長按事件,如果你不想讓這些長按事件先后都觸發
 9 //  可以使用本類加以控制
10 
11 //  2014-04-08 增加區分手勢調用
12 
13 typedef enum {
14     LONG_PRESS_VIEW_DEMO = 1,         
15 }LONG_PRESS_VIEW;
16 
17 #import <Foundation/Foundation.h>
18 
19 @interface LongPressControl : NSObject
20 {
21     NSMutableArray *_arrayLongPressView;
22 }
23 
24 #pragma mark
25 #pragma mark-------------創建 銷毀---------------------
26 /**   函數名稱 :shareInfo
27  **   函數作用 :創建 LongPressControl 單例對象
28  **   函數參數 :
29  **   函數返回值:URLog 單例對象
30  **/
31 +(LongPressControl *)shareInfo;
32 
33 /**   函數名稱 :freeInfo
34  **   函數作用 :釋放 LongPressControl 單例對象
35  **   函數參數 :
36  **   函數返回值:
37  **/
38 +(void)freeInfo;
39 
40 /*!
41  *  TODO:添加長按事件
42  *
43  *  @param view 調用的view
44  *
45  *  @author pigpigdaddy
46  */
47 - (void)addLongPressAction:(LONG_PRESS_VIEW)view;
48 
49 /*!
50  *  TODO:刪除長按事件
51  *
52  *  @param view 調用的view
53  *
54  *  @author pigpigdaddy
55  */
56 - (void)removeLongPressAction:(LONG_PRESS_VIEW)view;
57 
58 /*!
59  *  TODO:是否存在長按事件
60  *
61  *  @param view 是那個View
62  *
63  *  @return
64  *
65  *  @author pigpigdaddy
66  */
67 - (BOOL)isExistLongPressAction:(LONG_PRESS_VIEW)view;
68 
69 @end

LONG_PRESS_VIEW這個Type,用於記錄並區分當前是哪個view需要這樣的控制,比如這個demo中就是LONG_PRESS_VIEW_DEMO,以后可以在類型中添加新的type。

_arrayLongPressView用於將Type類型添加進來,如果cell手勢響應,就添加相應view的type進來。

三個函數,分別在cell開始手勢時添加type、cell結束手勢時移除type、以及判斷當前view是否已經有cell正在被響應手勢。

這樣,這個單例就像是一把鎖,一旦手勢進入就上鎖,直到手勢結束才打開鎖。

來看一下我實際的democell的實現文件,如何處理手勢

 1 - (void)longPressAction:(UILongPressGestureRecognizer *)ges
 2 {
 3     switch (ges.state) {
 4         case UIGestureRecognizerStateBegan:{
 5             NSLog(@"%@",[NSString stringWithFormat:@"%d===%d", self.indexPath.section, self.indexPath.row]);
 6         }
 7             break;
 8         case UIGestureRecognizerStateChanged:{
 9             
10         }
11             break;
12         case UIGestureRecognizerStateEnded:{
13             [[LongPressControl shareInfo] removeLongPressAction:LONG_PRESS_VIEW_DEMO];
14         }
15             break;
16         case UIGestureRecognizerStateCancelled:{
17             [[LongPressControl shareInfo] removeLongPressAction:LONG_PRESS_VIEW_DEMO];
18         }
19             break;
20         case UIGestureRecognizerStateFailed:{
21             [[LongPressControl shareInfo] removeLongPressAction:LONG_PRESS_VIEW_DEMO];
22         }
23             break;
24             
25         default:
26             break;
27     }
28 }
29 
30 - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
31 {
32     if (gestureRecognizer != self.longPressGes) {
33         return NO;
34     }else if ([[LongPressControl shareInfo] isExistLongPressAction:LONG_PRESS_VIEW_DEMO]){
35         return NO;
36     }else{
37         [[LongPressControl shareInfo] addLongPressAction:LONG_PRESS_VIEW_DEMO];
38         return YES;
39     }
40 }

如此,我的collectionView中的多個cell,不再同時響應多個cell的手勢,而且同時長按時,也只有第一個cell會響應長按手勢。工作良好!

請參考demo(這里https://github.com/pigpigdaddy/LongPressSingleDemo

 

另外,我遇到一個問題,就是

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer 函數每次進入的時候,都會有一個仿佛“collectionViewCell自帶的長按手勢(_handleGestureRecognizer)”會進入,我參看了UICollectionViewCell的.h文件,其中聲明了@class UILongPressGestureRecognizer;但並沒有發現有任何關於手勢的接口,很奇怪,是iOS的保留節目嗎?有知道的可以幫忙解釋一下嗎?感謝!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM