iOS 之UITapGestureRecognizer活学活用

来源:互联网 发布:日本tpp知乎 编辑:程序博客网 时间:2024/06/05 02:22

一、从零开始创建项目

1.为了大家方便理解,我们从一个空项目开始创建


2.项目的配置情况如下,可以根据自己随意调整


3. 因为我们创建的是新项目,除了一个ILAppDelegate什么都没有


4.正常情况下我们会创建一个根RootViewController,然后通过Controller控制视图的显示逻辑,这里只是一个练习,我们尝试一下新的作法,不要MVC模型了


没有Controller.....

5.我们在屏幕上看到的就是IOS的视图,所有的可显示组件都是UIView的子类(底层的先不考虑)包括UIWindow,其中UIWindow的一个方法

[cpp] view plaincopy
  1. - (void)makeKeyAndVisible;   


官方给的解释如下:
convenience. most apps call this to show the main window and also make it key.
所以我们要做的就是创建一系列的视图并把这些视图加入到一个UIWindow中,最后将UIWindow显示到屏幕上

思路有了,下一步就是具体的实现


在ILTapWindow.m中实现如下代码

[objc] view plaincopy在CODE上查看代码片派生到我的代码片
  1. - (id)initWithFrame:(CGRect)frame  
  2. {  
  3.     self = [super initWithFrame:frame];  
  4.     if (self) {  
  5.         [self doInit];  
  6.     }  
  7.     return self;  
  8. }  
  9.   
  10. - (void)doInit  
  11. {  
  12.     //创建一个测试的View,我们将手势添加到这个绿色的View上  
  13.     UIView *greenView = [[UIView alloc] initWithFrame:self.bounds];  
  14.     greenView.backgroundColor = [UIColor greenColor];  
  15.     //将greenView添加到当前window上  
  16.     [self addSubview:greenView];  
  17.       
  18.     //创建一个Tap手势  
  19.     UITapGestureRecognizer *gesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)];  
  20.     //将手势添加到greenView上,这样才将手势与view关联起来  
  21.     [greenView addGestureRecognizer:gesture];  
  22. }  
  23.   
  24. - (void)handleTap:(UITapGestureRecognizer *)gesture  
  25. {  
  26.     //我们获取gesture关联的view,并将view的类名打印出来  
  27.     NSString *className = NSStringFromClass([gesture.view class]);  
  28.     NSLog(@"您点击了%@", className);  
  29. }  



这样我们就将视图及手势相关逻辑处理好了,下一步我们要将ILTapWindow显示在屏幕上,回到ILAppDelegate.m的入口方法

[objc] view plaincopy在CODE上查看代码片派生到我的代码片
  1. - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions  
  2. {  
  3.     self.window = [[ILTapWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];  
  4.     [self.window makeKeyAndVisible];  
  5.     return YES;  
  6. }  



6.所有逻辑基本都写好了,我们点击运行一下吧(项目下载地址:http://git.oschina.net/green/ILTapGestureRecognizer/repository/archive?ref=第一部分)



二、通过附加透明View实现区域性识别方法

1.看起来好像没有什么难度,大体思路不就是把UITapGestureRecognizer加到UIView中。事实确实是这样的,可问题又来了,如果我想将手势添加到绿色视图的下半部分


2.思考了一会儿,好像确实不那么好处理


但是这点可难不到我广大程序员,于是Baidu Google,后给出一个答案,添加一个透明的UIView,将UITapGestureRecognizer添加到这个透明的UIView不就可以了


面包和馒头都会有的

3.动手实现

[objc] view plaincopy在CODE上查看代码片派生到我的代码片
  1. @implementation ILTapWindow  
  2.   
  3. - (id)initWithFrame:(CGRect)frame  
  4. {  
  5.     self = [super initWithFrame:frame];  
  6.     if (self) {  
  7.         [self doInit];  
  8.     }  
  9.     return self;  
  10. }  
  11.   
  12. - (void)doInit  
  13. {  
  14.     //创建一个测试的View,我们将手势添加到这个绿色的View上  
  15.     UIView *greenView = [[UIView alloc] initWithFrame:self.bounds];  
  16.     greenView.backgroundColor = [UIColor greenColor];  
  17.     //将greenView添加到当前window上  
  18.     [self addSubview:greenView];  
  19.     CGRect bounds= greenView.bounds;  
  20.     CGRect tapArea = CGRectMake(0, CGRectGetHeight(bounds) / 2, CGRectGetWidth(bounds), CGRectGetHeight(bounds));  
  21.     [self addGestureArea:tapArea forView:greenView];  
  22.      
  23. }  
  24.   
  25. - (void)addGestureArea:(CGRect)frame forView:(UIView *)view  
  26. {  
  27.     UIView *gestureView = [[UIView alloc] initWithFrame:frame];  
  28.     //此处将设置为[UIColor clearColor]UIView会变为透明,这里为了测试方便把color设为红色  
  29.     gestureView.backgroundColor = [UIColor redColor];  
  30.     //创建一个Tap手势  
  31.     UITapGestureRecognizer *gesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)];  
  32.     //将手势添加到greenView上,这样才将手势与view关联起来  
  33.     [gestureView addGestureRecognizer:gesture];  
  34.       
  35.     [view addSubview:gestureView];  
  36.       
  37. }  
  38.   
  39. - (void)handleTap:(UITapGestureRecognizer *)gesture  
  40. {  
  41.     //我们获取gesture关联的view,并将view的类名打印出来  
  42.     NSString *className = NSStringFromClass([gesture.view class]);  
  43.     NSLog(@"您点击了%@", className);  
  44. }  
  45.   
  46. @end  



执行一下(项目下载地址 http://git.oschina.net/green/ILTapGestureRecognizer/repository/archive?ref=第二部分)


4.需求总是再变的,一天设计师要求点击屏幕,在上方推出工具条,再次点击屏幕隐藏工具条,快速实现一下:

[objc] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #import "ILTapWindow.h"  
  2. #define TOOLS_VIEW_HEIGHT (44 + 10)  
  3.   
  4. @interface ILTapWindow ()  
  5. //用于保存工具条的指针  
  6. @property (weak, nonatomicUIView *toolsBar;  
  7. @end  
  8.   
  9. @implementation ILTapWindow  
  10.   
  11. - (id)initWithFrame:(CGRect)frame  
  12. {  
  13.     self = [super initWithFrame:frame];  
  14.     if (self) {  
  15.         [self doInit];  
  16.     }  
  17.     return self;  
  18. }  
  19.   
  20. - (void)doInit  
  21. {  
  22.     [self configBackgroundView];  
  23.     [self configToolsBar];  
  24.       
  25. }  
  26.   
  27. - (void)configBackgroundView  
  28. {  
  29.     //创建一个测试的View,我们将手势添加到这个绿色的View上  
  30.     UIView *greenView = [[UIView alloc] initWithFrame:self.bounds];  
  31.     greenView.backgroundColor = [UIColor greenColor];  
  32.     //将greenView添加到当前window上  
  33.     [self addSubview:greenView];  
  34.     [self addGestureArea:greenView.bounds forView:greenView];  
  35. }  
  36.   
  37. - (void)configToolsBar  
  38. {  
  39.     CGRect frame = CGRectMake(0, -TOOLS_VIEW_HEIGHT, CGRectGetWidth(self.frame), TOOLS_VIEW_HEIGHT);  
  40.     UIView *tools = [[UIView alloc] initWithFrame:frame];  
  41.     tools.backgroundColor = [UIColor yellowColor];  
  42.     [self addSubview:tools];  
  43.     UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];  
  44.     button.backgroundColor = [UIColor blueColor];  
  45.     button.frame = CGRectMake(10104040);  
  46.     [button setTitle:@"打印" forState:UIControlStateNormal];  
  47.     [button addTarget:self action:@selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];  
  48.     [tools addSubview:button];  
  49.     self.toolsBar = tools;  
  50. }  
  51.   
  52. - (void)buttonPressed:(UIButton *)button  
  53. {  
  54.     NSLog(@"=============点击了Button==============");  
  55.       
  56. }  
  57.   
  58. - (void)showToolsBar:(BOOL)show  
  59. {  
  60.     CGRect frame = self.toolsBar.frame;  
  61.     frame.origin.y = show ? 0 : -TOOLS_VIEW_HEIGHT;  
  62.     [UIView animateWithDuration:0.3 animations:^{  
  63.         self.toolsBar.frame = frame;  
  64.     }];  
  65. }  
  66.   
  67.   
  68. - (void)addGestureArea:(CGRect)frame forView:(UIView *)view  
  69. {  
  70.     UIView *gestureView = [[UIView alloc] initWithFrame:frame];  
  71.     gestureView.backgroundColor = [UIColor clearColor];  
  72.     //创建一个Tap手势  
  73.     UITapGestureRecognizer *gesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)];  
  74.     //将手势添加到greenView上,这样才将手势与view关联起来  
  75.     gesture.cancelsTouchesInView = NO;  
  76.     gesture.delaysTouchesBegan = YES;  
  77.     [gestureView addGestureRecognizer:gesture];  
  78.       
  79.     [view addSubview:gestureView];  
  80.       
  81. }  
  82.   
  83. - (BOOL)isToolsBarShow  
  84. {  
  85.     //在ios中CGFloat做了优化,是可以直接用==来进行比较,C++不可以  
  86.     return self.toolsBar.frame.origin.y == 0;  
  87. }  
  88.   
  89. - (void)handleTap:(UITapGestureRecognizer *)gesture  
  90. {  
  91.     NSLog(@"================点击了屏幕,显隐工具条=========================");  
  92.     if (self.isToolsBarShow) {  
  93.         [self showToolsBar:NO];  
  94.     } else {  
  95.         [self showToolsBar:YES];  
  96.     }  
  97.       
  98. }  
  99.   
  100. @end  


结果正如我们希望的那样,点击屏幕显示工具条,再次点击屏幕隐藏工具条。当工具条显示时,我们点击工具条,没有触发手势的点击事件。可是事与愿为,真实的情况并不是这样的,这次我们为了简便直接使用了UIWindow的方法显示UIView,通常情况下,我们的视图的控制是交给UIViewController来处理的,在使用UIViewController的时候,如果工具条是在显示状态时,我们点击工具条也会触发手势点击事件,这个留给大家去测试了,代码只需要稍微修改就能测试出来。(工具条部分下载地址:http://git.oschina.net/green/ILTapGestureRecognizer/repository/archive?ref=第二部分-工具条)

三、通过委托实现区域性识别

1.我们知道通过附加透明UIView的方法并不是总起作用,虽然在本次示例中没有问题,但是通过UIViewController管理视图时,就会出现视图穿透的效果,即在底层UIView加了手势,点击上面的UIView也会触发点击手势事件,这并不是我们想要的结果。在另一方面,附加透明UIView的做法在一些情况下,如不想中间区域响应手势点击。这样的话,就得加多个透明的UIView才能实现,有没有更好的方法吗?

我们新建一个类,继承如下:


ILTapGestureRecognizer代码如下:

[objc] view plaincopy在CODE上查看代码片派生到我的代码片
  1. @interface ILTapGestureRecognizer : UITapGestureRecognizer  
  2.   
  3. @property (unsafe_unretained, nonatomic)CGRect responseFrame;  
  4.   
  5. @end  
  6. ///////////////////////////////////////////////////////////////////  
  7. @interface ILTapGestureRecognizer () <UIGestureRecognizerDelegate>  
  8.   
  9. @end  
  10.   
  11. @implementation ILTapGestureRecognizer  
  12.   
  13. - (id)initWithTarget:(id)target action:(SEL)action  
  14. {  
  15.     self = [super initWithTarget:target action:action];  
  16.     if (self) {  
  17.         self.delegate = self;  
  18.     }  
  19.     return self;  
  20. }  
  21.   
  22. - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch  
  23. {  
  24.     //获取点击坐标  
  25.     CGPoint pointPosition = [touch locationInView:gestureRecognizer.view];  
  26.     if (CGRectContainsPoint(self.responseFrame, pointPosition)) {  
  27.         return YES;  
  28.     }  
  29.     return NO;  
  30. }  
  31.   
  32.   
  33. @end  



当然ILWindow.m文件也需要修改一下

[objc] view plaincopy在CODE上查看代码片派生到我的代码片
  1. @interface ILTapWindow ()  
  2. @end  
  3.   
  4. @implementation ILTapWindow  
  5.   
  6. - (id)initWithFrame:(CGRect)frame  
  7. {  
  8.     self = [super initWithFrame:frame];  
  9.     if (self) {  
  10.         [self doInit];  
  11.     }  
  12.     return self;  
  13. }  
  14.   
  15. - (void)doInit  
  16. {  
  17.     //创建一个测试的View,我们将手势添加到这个绿色的View上  
  18.     UIView *greenView = [[UIView alloc] initWithFrame:self.bounds];  
  19.     greenView.backgroundColor = [UIColor greenColor];  
  20.     //将greenView添加到当前window上  
  21.     [self addSubview:greenView];  
  22.       
  23.     ILTapGestureRecognizer *gesture = [[ILTapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)];  
  24.     CGRect bounds= greenView.bounds;  
  25.     CGRect tapArea = CGRectMake(0, CGRectGetHeight(bounds) / 2, CGRectGetWidth(bounds), CGRectGetHeight(bounds));  
  26.     gesture.responseFrame = tapArea;  
  27.       
  28.     [greenView addGestureRecognizer:gesture];  
  29. }  
  30.   
  31. - (void)handleTap:(UITapGestureRecognizer *)gesture  
  32. {  
  33.     //我们获取gesture关联的view,并将view的类名打印出来  
  34.     NSString *className = NSStringFromClass([gesture.view class]);  
  35.     NSLog(@"您点击了%@", className);  
  36. }  
  37.   
  38.   
  39. @end  



2.实现原理

通过UIGestureRecognizerDelegate的接口

[cpp] view plaincopy
  1. - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch;  



来决定是否响应手势的点击事件,官方解释如下:

called before touchesBegan:withEvent: is called on the gesture recognizer for a new touch. return NO to prevent the gesture recognizer from seeing this touch

至此点击手势我们就全部学习完了,在项目开发中,我们经常会遇到“三、通过委托实现区域性识别”,这里给的示例比较简单,项目中可能很复杂,我们可以通过定制ILTapGestureRecognizer来实现更加复杂的功能

0 0
原创粉丝点击