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的保留节目吗?有知道的可以帮忙解释一下吗?感谢!

iOS手势 规避同一界面上不同子界面同时响应多个手势,布布扣,bubuko.com

时间: 2024-10-25 22:48:17

iOS手势 规避同一界面上不同子界面同时响应多个手势的相关文章

WPF子界面向父界面传递带参数的委托

需求如下: 父界面上有几个按钮,需要在点击按钮的时候向父界面传值,以知道该控制哪个界面显示. 父界面:WIN1 子界面:WIN2 此处或者说是子控件向父控件传值 1.子界面定义委托 WIN1里写: public delegate void ChangeTextHandler(string text); public event ChangeTextHandler ChangeTextEvent; 2.父界面在加载了子界面之后,注册委托.必须在父界面load的时候或者之前注册 WIN2里写: uc

在UINavigationController自定义返回按钮后实现手势右滑到上一级界面(interactivePopGestureRecognizer)

在iOS7中,新增加了一个小小的功能,也就是这个self.navigationController.interactivePopGestureRecognizer. 1.情景概况: 在UINavigationController自定义返回按钮后无法实现手势右滑到上一级界面. 2.解决方案: self.navigationController.interactivePopGestureRecognizer.delegate 默认是<_UINavigationInteractiveTransitio

ios开发之--为父view上的子view添加阴影

项目中碰到一个问题,在tableview的headerview里面有很一个子view,设计师的要求是在下方添加一个阴影,效果如下: 以前的实现思路就是,代码如下: 添加阴影 调用视图的 layer CALayer *layer = [imageView layer]; layer.shadowOffset = CGSizeMake(0, 3); //(0,0)时是四周都有阴影 layer.shadowRadius = 5.0; layer.shadowColor = [UIColor black

iOS使用xib文件创建一个组件为子控件,进行复用

有些情况下,我们发现有一些界面上的控件是可以复用的 如果每次都拷贝这些控件过去,就是比较麻烦.所以,就用一个xib文件,创建一个view,把要复用的控件,放在里面组成一个view,然后在其他的ViewController里面引用就行了. 这样会方便很多. 第一步:创建一个SingleViewApplication,命名为“xib作为子控件复用”,在项目里New File,选择Cocoa Touch Class,命名为"AAView",点击Next,如图1所示: 图 1 第二步:创建一个

小胖说事9------iOS xcode6中新建空工程和在iPhone5s上的程序界面只有iPhone4上的大小

升级xcode6之后,直接建立Empty工程后发现,这是太坑,真的是什么都没有啊.只能换个方法了 总结如下: 1.新建一个single view application 2.打开 Info.plist(别告诉我不知道去哪里找info.plist),删除里面的 Launch screen interface file base name以及 Main Main storyboard file base name 3.删除Main.storyboard以及LaunchScreen.xib 4.修改A

c# winform 循环遍历界面上的所有控件,foreach,Controls,AllowDrop

foreach (System.Windows.Forms.Control control in this.groupBox2.Controls)//遍历groupBox2上的所有控件 { if (control is System.Windows.Forms.PictureBox) { System.Windows.Forms.PictureBox pb = (System.Windows.Forms.PictureBox)control; pb.AllowDrop = true; } if

基于MVC+EasyUI的Web开发框架经验总结(10)--在Web界面上实现数据的导入和导出

数据的导入导出,在很多系统里面都比较常见,这个导入导出的操作,在Winform里面比较容易实现,我曾经在之前的一篇文章<Winform开发框架之通用数据导入导出操作>介绍了在Winform里面的通用导入导出模块的设计和开发过程,但在Web上我们应该如何实现呢?本文主要介绍利用MVC4+EasyUI的特点,并结合文件上传控件Uploadify 的使用,实现文件上传后马上进行处理并显示,然后确认后把数据写入数据库的过程. 我们知道,Web上对Excel的处理和Winform的有所差异,如果是在We

FMX相当于在界面上自己又做了一个小操作系统

FMX的自画界面我也不看好,比如复制粘贴,太丑了,系统做得很好很精细的复制粘贴界面,就是无法调出,比如MIUI,复制粘贴还能有个放大镜,可以选择到屏幕边缘的文字,可以选择剪贴板内多个可粘贴的文字:还有那个Memo,有的时候该折行的不折行,有的文字看不到了.文本输入框,隐藏剪贴板后,再点击就弹不出来了:系统本身的文本框就没有这个问题.底部输入框输入时自动上移界面,好像是操作系统本身就有的吧,FMX还得自己编很多代码,也不一定编好.自己编码补漏洞是另外一回事.FMX给我的感觉是在界面上自己又做了一个

iOS-响应上下左右滑动手势

iOS-响应上下左右滑动手势 分类: iPhone开发2012-03-17 14:42 25489人阅读 评论(8) 收藏 举报 iosup -(void)viewDidLoad{ UISwipeGestureRecognizer *recognizer; recognizer = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(handleSwipeFrom:)]; [recognizer setDir