一、从零开始创建项目
1.为了大家方便理解,我们从一个空项目开始创建
2.项目的配置情况如下,可以根据自己随意调整
3. 因为我们创建的是新项目,除了一个ILAppDelegate什么都没有
4.正常情况下我们会创建一个根RootViewController,然后通过Controller控制视图的显示逻辑,这里只是一个练习,我们尝试一下新的作法,不要MVC模型了
没有Controller.....
5.我们在屏幕上看到的就是IOS的视图,所有的可显示组件都是UIView的子类(底层的先不考虑)包括UIWindow,其中UIWindow的一个方法
- - (void)makeKeyAndVisible;
convenience. most apps call this to show the main window and also make it key.所以我们要做的就是创建一系列的视图并把这些视图加入到一个UIWindow中,最后将UIWindow显示到屏幕上
思路有了,下一步就是具体的实现
在ILTapWindow.m中实现如下代码
- - (id)initWithFrame:(CGRect)frame
- {
- self = [super initWithFrame:frame];
- if (self) {
- [self doInit];
- }
- return self;
- }
- - (void)doInit
- {
- //创建一个测试的View,我们将手势添加到这个绿色的View上
- UIView *greenView = [[UIView alloc] initWithFrame:self.bounds];
- greenView.backgroundColor = [UIColor greenColor];
- //将greenView添加到当前window上
- [self addSubview:greenView];
- //创建一个Tap手势
- UITapGestureRecognizer *gesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)];
- //将手势添加到greenView上,这样才将手势与view关联起来
- [greenView addGestureRecognizer:gesture];
- }
- - (void)handleTap:(UITapGestureRecognizer *)gesture
- {
- //我们获取gesture关联的view,并将view的类名打印出来
- NSString *className = NSStringFromClass([gesture.view class]);
- NSLog(@"您点击了%@", className);
- }
- - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
- {
- self.window = [[ILTapWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
- [self.window makeKeyAndVisible];
- return YES;
- }
二、通过附加透明View实现区域性识别方法
1.看起来好像没有什么难度,大体思路不就是把UITapGestureRecognizer加到UIView中。事实确实是这样的,可问题又来了,如果我想将手势添加到绿色视图的下半部分
2.思考了一会儿,好像确实不那么好处理
但是这点可难不到我广大程序员,于是Baidu Google,后给出一个答案,添加一个透明的UIView,将UITapGestureRecognizer添加到这个透明的UIView不就可以了
面包和馒头都会有的
3.动手实现
- @implementation ILTapWindow
- - (id)initWithFrame:(CGRect)frame
- {
- self = [super initWithFrame:frame];
- if (self) {
- [self doInit];
- }
- return self;
- }
- - (void)doInit
- {
- //创建一个测试的View,我们将手势添加到这个绿色的View上
- UIView *greenView = [[UIView alloc] initWithFrame:self.bounds];
- greenView.backgroundColor = [UIColor greenColor];
- //将greenView添加到当前window上
- [self addSubview:greenView];
- CGRect bounds= greenView.bounds;
- CGRect tapArea = CGRectMake(0, CGRectGetHeight(bounds) / 2, CGRectGetWidth(bounds), CGRectGetHeight(bounds));
- [self addGestureArea:tapArea forView:greenView];
- }
- - (void)addGestureArea:(CGRect)frame forView:(UIView *)view
- {
- UIView *gestureView = [[UIView alloc] initWithFrame:frame];
- //此处将设置为[UIColor clearColor]UIView会变为透明,这里为了测试方便把color设为红色
- gestureView.backgroundColor = [UIColor redColor];
- //创建一个Tap手势
- UITapGestureRecognizer *gesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)];
- //将手势添加到greenView上,这样才将手势与view关联起来
- [gestureView addGestureRecognizer:gesture];
- [view addSubview:gestureView];
- }
- - (void)handleTap:(UITapGestureRecognizer *)gesture
- {
- //我们获取gesture关联的view,并将view的类名打印出来
- NSString *className = NSStringFromClass([gesture.view class]);
- NSLog(@"您点击了%@", className);
- }
- @end
4.需求总是再变的,一天设计师要求点击屏幕,在上方推出工具条,再次点击屏幕隐藏工具条,快速实现一下:
- #import "ILTapWindow.h"
- #define TOOLS_VIEW_HEIGHT (44 + 10)
- @interface ILTapWindow ()
- //用于保存工具条的指针
- @property (weak, nonatomic) UIView *toolsBar;
- @end
- @implementation ILTapWindow
- - (id)initWithFrame:(CGRect)frame
- {
- self = [super initWithFrame:frame];
- if (self) {
- [self doInit];
- }
- return self;
- }
- - (void)doInit
- {
- [self configBackgroundView];
- [self configToolsBar];
- }
- - (void)configBackgroundView
- {
- //创建一个测试的View,我们将手势添加到这个绿色的View上
- UIView *greenView = [[UIView alloc] initWithFrame:self.bounds];
- greenView.backgroundColor = [UIColor greenColor];
- //将greenView添加到当前window上
- [self addSubview:greenView];
- [self addGestureArea:greenView.bounds forView:greenView];
- }
- - (void)configToolsBar
- {
- CGRect frame = CGRectMake(0, -TOOLS_VIEW_HEIGHT, CGRectGetWidth(self.frame), TOOLS_VIEW_HEIGHT);
- UIView *tools = [[UIView alloc] initWithFrame:frame];
- tools.backgroundColor = [UIColor yellowColor];
- [self addSubview:tools];
- UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
- button.backgroundColor = [UIColor blueColor];
- button.frame = CGRectMake(10, 10, 40, 40);
- [button setTitle:@"打印" forState:UIControlStateNormal];
- [button addTarget:self action:@selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
- [tools addSubview:button];
- self.toolsBar = tools;
- }
- - (void)buttonPressed:(UIButton *)button
- {
- NSLog(@"=============点击了Button==============");
- }
- - (void)showToolsBar:(BOOL)show
- {
- CGRect frame = self.toolsBar.frame;
- frame.origin.y = show ? 0 : -TOOLS_VIEW_HEIGHT;
- [UIView animateWithDuration:0.3 animations:^{
- self.toolsBar.frame = frame;
- }];
- }
- - (void)addGestureArea:(CGRect)frame forView:(UIView *)view
- {
- UIView *gestureView = [[UIView alloc] initWithFrame:frame];
- gestureView.backgroundColor = [UIColor clearColor];
- //创建一个Tap手势
- UITapGestureRecognizer *gesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)];
- //将手势添加到greenView上,这样才将手势与view关联起来
- gesture.cancelsTouchesInView = NO;
- gesture.delaysTouchesBegan = YES;
- [gestureView addGestureRecognizer:gesture];
- [view addSubview:gestureView];
- }
- - (BOOL)isToolsBarShow
- {
- //在ios中CGFloat做了优化,是可以直接用==来进行比较,C++不可以
- return self.toolsBar.frame.origin.y == 0;
- }
- - (void)handleTap:(UITapGestureRecognizer *)gesture
- {
- NSLog(@"================点击了屏幕,显隐工具条=========================");
- if (self.isToolsBarShow) {
- [self showToolsBar:NO];
- } else {
- [self showToolsBar:YES];
- }
- }
- @end
结果正如我们希望的那样,点击屏幕显示工具条,再次点击屏幕隐藏工具条。当工具条显示时,我们点击工具条,没有触发手势的点击事件。可是事与愿为,真实的情况并不是这样的,这次我们为了简便直接使用了UIWindow的方法显示UIView,通常情况下,我们的视图的控制是交给UIViewController来处理的,在使用UIViewController的时候,如果工具条是在显示状态时,我们点击工具条也会触发手势点击事件,这个留给大家去测试了,代码只需要稍微修改就能测试出来。(工具条部分下载地址:http://git.oschina.net/green/ILTapGestureRecognizer/repository/archive?ref=第二部分-工具条)
三、通过委托实现区域性识别
1.我们知道通过附加透明UIView的方法并不是总起作用,虽然在本次示例中没有问题,但是通过UIViewController管理视图时,就会出现视图穿透的效果,即在底层UIView加了手势,点击上面的UIView也会触发点击手势事件,这并不是我们想要的结果。在另一方面,附加透明UIView的做法在一些情况下,如不想中间区域响应手势点击。这样的话,就得加多个透明的UIView才能实现,有没有更好的方法吗?
我们新建一个类,继承如下:
ILTapGestureRecognizer代码如下:
- @interface ILTapGestureRecognizer : UITapGestureRecognizer
- @property (unsafe_unretained, nonatomic)CGRect responseFrame;
- @end
- ///
- @interface ILTapGestureRecognizer () <UIGestureRecognizerDelegate>
- @end
- @implementation ILTapGestureRecognizer
- - (id)initWithTarget:(id)target action:(SEL)action
- {
- self = [super initWithTarget:target action:action];
- if (self) {
- self.delegate = self;
- }
- return self;
- }
- - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
- {
- //获取点击坐标
- CGPoint pointPosition = [touch locationInView:gestureRecognizer.view];
- if (CGRectContainsPoint(self.responseFrame, pointPosition)) {
- return YES;
- }
- return NO;
- }
- @end
- @interface ILTapWindow ()
- @end
- @implementation ILTapWindow
- - (id)initWithFrame:(CGRect)frame
- {
- self = [super initWithFrame:frame];
- if (self) {
- [self doInit];
- }
- return self;
- }
- - (void)doInit
- {
- //创建一个测试的View,我们将手势添加到这个绿色的View上
- UIView *greenView = [[UIView alloc] initWithFrame:self.bounds];
- greenView.backgroundColor = [UIColor greenColor];
- //将greenView添加到当前window上
- [self addSubview:greenView];
- ILTapGestureRecognizer *gesture = [[ILTapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)];
- CGRect bounds= greenView.bounds;
- CGRect tapArea = CGRectMake(0, CGRectGetHeight(bounds) / 2, CGRectGetWidth(bounds), CGRectGetHeight(bounds));
- gesture.responseFrame = tapArea;
- [greenView addGestureRecognizer:gesture];
- }
- - (void)handleTap:(UITapGestureRecognizer *)gesture
- {
- //我们获取gesture关联的view,并将view的类名打印出来
- NSString *className = NSStringFromClass([gesture.view class]);
- NSLog(@"您点击了%@", className);
- }
- @end
通过UIGestureRecognizerDelegate的接口
- - (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来实现更加复杂的功能