iOS开发之UI篇(4)—— 触摸事件
来源:互联网 发布:adobe flash cs6 mac 编辑:程序博客网 时间:2024/06/13 05:16
版本
Xcode 9.1
UIApplication、UIViewController、UIView均继承自UIResponder。
在iOS中,只有继承了UIResponder的对象才能接收处理事件,此对象即为事件“响应者”。
接下来从响应方法、触摸对象UITouch、事件对象UIEvent和响应链这四个方面进一步分析。然后写个示例,也就算了。
1. 响应方法
UIResponder中提供了五个响应方法来处理触摸事件:
// 一根或多根手指触摸开始- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;// 一根或多根手指触摸移动(多次调用)- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;// 一根或多根手指触摸结束- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;// 触摸取消(某个系统事件(例如电话呼入)会打断触摸过程)- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;/** 当无法获得touches真实值的时候调用该方法(iOS9.1开始引入) 当UIKit无法得到准确的touches值的时候(例如触摸笔处在屏幕边缘,此时无法获得触摸笔的高度和定位), 会生成此touches的预估值,导致estimatedPropertiesExpectingUpdates这个属性发生改变, 当属性estimatedPropertiesExpectingUpdates发生改变(不为空或者更新)时,调用该方法 */- (void)touchesEstimatedPropertiesUpdated:(NSSet<UITouch *> *)touches NS_AVAILABLE_IOS(9_1);
2. 触摸对象UITouch
当手指触摸屏幕时,会创建一个与手指相关的UITouch对象,且一根手指对应一个对象。
如果多根手指同时触摸屏幕,那么会依次创建多个对象,这些对象会被包含在响应方法的形参touches里面。
UITouch中包含的常用信息有:
window属性:触摸时所在的窗口
view属性:触摸时所在视图
tapCount属性:短时间内点击的次数(可判断单点还是多点)
timestamp属性:触摸产生或变化的时间戳
phase属性:触摸周期内的各个状态
locationInView:方法:取得在指定视图的位置
previousLocationInView:方法:取得移动的前一个位置
3. 事件对象UIEvent
当发生一个事件时,就会对应产生一个UIEvent对象。
在一次完整的触摸过程中,只会产生一个UIEvent,也就是说,五个响应方法都是同一个UIEvent对象(即响应方法的形参event)。
UIEvent中包含的常用信息有:
type属性:事件类型
timestamp属性:事件产生的时间
touchesForWindow:方法:返回当前窗口上的触摸对象UITouch
touchesForView:方法:返回特定视图上的触摸对象UITouch
4. 响应链
前面讲到UIApplication、UIViewController、UIView均能响应触摸事件,当有多个view重叠的时候触摸事件是怎样响应的呢?
图解:
触摸事件响应链
- 当一个事件发生后首先看initial view能否处理这个事件,如果不能则会将事件传递给其上级视图(inital view的superView);
- 如果上级视图(黄色view)仍然无法处理则会继续往上传递;
- 一直传递到视图控制器view controller,首先判断视图控制器的根视图(蓝色view)是否能处理此事件;
- 如果不能则接着判断该视图控制器view controller能否处理此事件,如果还是不能则继续向上传递;
- 一直到window,如果window还是不能处理此事件则继续交给application(UIApplication单例对象)处理;
- 如果最后application还是不能处理此事件则将其丢弃。
在这个过程中各个对象如何知道自己能不能处理该事件呢?对于继承UIResponder的对象,其不能处理事件有几个条件:
- userInteractionEnabled = NO(其子视图也将无法响应事件)
- hidden = YES
- alpha = 0~0.01
- 没有实现开始触摸方法(touchesBegan:withEvent:)
注:前三点都是针对UIView控件或其子控件而言的
示例
在ViewController的子视图(self.view)上面依次添加三个view:GreenView 、BlueView 和RedView。ViewController和这三个view均实现触摸方法,其中在三个view的触摸移动方法中均设置该view中心点跟随触摸点移动(这样我们触摸移动哪个view时,这个view就会跟随触摸点移动),在ViewController的触摸移动方法中均设置背景颜色随机变化。下面结合效果图来解析:
- 触摸RedView时,由于RedView中设置了userInteractionEnabled = No,使得RedView并没有响应事件(相对于父视图移动),而是将事件传递到父视图(BlueView),由父视图响应事件;
- 触摸BlueView 时,BlueView响应了触摸事件(相对于父视图移动),没有将事件传递给它的父视图(GreenView),所以拖动BlueView时,GreenView并没有动;
- 触摸GreenView时,GreenView响应了触摸事件(相对于父视图移动),由于在GreenView的touchesBegan方法里将事件传递给下一个响应者,使得ViewController也响应了事件(背景颜色随机改变)。
效果图
RedView.m
- (void)drawRect:(CGRect)rect { self.userInteractionEnabled = NO;// self.hidden = YES;// self.alpha = 0.5;}#pragma mark - 触摸事件响应方法// 触摸开始- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { NSLog(@"RedView:touchesBegan");}// 触摸移动中(随着手指的移动,会多次调用该方法)- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { NSLog(@"RedView:touchesMoved"); /* 设置当前view随手指移动 */ // 取得一个触摸对象(对于多点触摸可能有多个对象) UITouch *touch = [touches anyObject]; // 取得触摸点在当前视图中的位置 CGPoint current = [touch locationInView:self]; // 取得前一个触摸点位置 CGPoint previous = [touch previousLocationInView:self]; // 触摸点移动偏移量 CGPoint offset = CGPointMake(current.x-previous.x, current.y-previous.y); // 当前视图移动前的中点位置(相对于父视图) CGPoint center = self.center; // 重新设置当前视图新位置 self.center = CGPointMake(center.x+offset.x, center.y+offset.y);}// 触摸结束- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { NSLog(@"RedView:touchesEnded");}// 触摸被取消(触摸结束前,某个系统事件(例如电话呼入)会打断触摸过程)- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { NSLog(@"RedView:touchesCancelled");}// 当无法获得touches真实值的时候调用该方法(一般使用触摸笔才出现此状况)- (void)touchesEstimatedPropertiesUpdated:(NSSet<UITouch *> *)touches { NSLog(@"RedView:touchesEstimatedPropertiesUpdated");}
BlueView.m
#pragma mark - 触摸事件响应方法// 触摸开始- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { NSLog(@"BlueView:touchesBegan");}// 触摸移动中(随着手指的移动,会多次调用该方法)- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { NSLog(@"BlueView:touchesMoved"); /* 设置当前view随手指移动 */ // 取得一个触摸对象(对于多点触摸可能有多个对象) UITouch *touch = [touches anyObject]; // 取得触摸点在当前视图中的位置 CGPoint current = [touch locationInView:self]; // 取得前一个触摸点位置 CGPoint previous = [touch previousLocationInView:self]; // 触摸点移动偏移量 CGPoint offset = CGPointMake(current.x-previous.x, current.y-previous.y); // 当前视图移动前的中点位置(相对于父视图) CGPoint center = self.center; // 重新设置当前视图新位置 self.center = CGPointMake(center.x+offset.x, center.y+offset.y);}// 触摸结束- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { NSLog(@"BlueView:touchesEnded");}// 触摸被取消(触摸结束前,某个系统事件(例如电话呼入)会打断触摸过程)- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { NSLog(@"BlueView:touchesCancelled");}// 当无法获得touches真实值的时候调用该方法(一般使用触摸笔才出现此状况)- (void)touchesEstimatedPropertiesUpdated:(NSSet<UITouch *> *)touches { NSLog(@"BlueView:touchesEstimatedPropertiesUpdated");}
GreenView.m
#pragma mark - 触摸事件响应方法// 触摸开始- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { NSLog(@"GreenView:touchesBegan"); // 传递触摸事件给下一响应者 [super touchesBegan:touches withEvent:event]; // 用[self nextResponder]传递过去的事件只响应touchesBegan,而不响应touchesMoved、touchesEnded等// [[self nextResponder] touchesBegan:touches withEvent:event];}// 触摸移动中(随着手指的移动,会多次调用该方法)- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { NSLog(@"GreenView:touchesMoved"); /* 设置当前view随手指移动 */ // 取得一个触摸对象(对于多点触摸可能有多个对象) UITouch *touch = [touches anyObject]; // 取得触摸点在当前视图中的位置 CGPoint current = [touch locationInView:self]; // 取得前一个触摸点位置 CGPoint previous = [touch previousLocationInView:self]; // 触摸点移动偏移量 CGPoint offset = CGPointMake(current.x-previous.x, current.y-previous.y); // 当前视图移动前的中点位置(相对于父视图) CGPoint center = self.center; // 重新设置当前视图新位置 self.center = CGPointMake(center.x+offset.x, center.y+offset.y);}// 触摸结束- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { NSLog(@"GreenView:touchesEnded");}// 触摸被取消(触摸结束前,某个系统事件(例如电话呼入)会打断触摸过程)- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { NSLog(@"GreenView:touchesCancelled");}// 当无法获得touches真实值的时候调用该方法(一般使用触摸笔才出现此状况)- (void)touchesEstimatedPropertiesUpdated:(NSSet<UITouch *> *)touches { NSLog(@"GreenView:touchesEstimatedPropertiesUpdated");}
ViewController.m
#pragma mark - 触摸事件响应方法// 触摸开始- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { NSLog(@"ViewController:touchesBegan");}// 触摸移动中(随着手指的移动,会多次调用该方法)- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { NSLog(@"ViewController:touchesMoved"); // 设置背景随机颜色 CGFloat red = (CGFloat)random() / (CGFloat)RAND_MAX; CGFloat green = (CGFloat)random() / (CGFloat)RAND_MAX; CGFloat blue = (CGFloat)random() / (CGFloat)RAND_MAX; self.view.backgroundColor = [UIColor colorWithRed:red green:green blue:blue alpha:1.0f];}// 触摸结束- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { NSLog(@"ViewController:touchesEnded");}// 触摸被取消(触摸结束前,某个系统事件(例如电话呼入)会打断触摸过程)- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { NSLog(@"ViewController:touchesCancelled");}/** 当无法获得touches真实值的时候调用该方法(一般使用触摸笔才出现此状况) 当UIKit无法得到准确的touches值的时候(例如触摸笔处在屏幕边缘,此时无法获得触摸笔的高度和定位), 会生成此touches的预估值,导致estimatedPropertiesExpectingUpdates这个属性发生改变, 当属性estimatedPropertiesExpectingUpdates发生改变(不为空或者更新)时,调用该方法 @param touches 触摸对象 */- (void)touchesEstimatedPropertiesUpdated:(NSSet<UITouch *> *)touches { NSLog(@"ViewController:touchesEstimatedPropertiesUpdated");}
- iOS开发之UI篇(4)—— 触摸事件
- 猫猫学IOS(二十五)UI之触摸事件
- AJ学IOS(25)UI之触摸事件
- iOS之UI高级---触摸事件
- UI之触摸事件
- IOS开发UI系列之事件、触摸、手势和响应者链
- ios开发系列之触摸事件
- iOS开发系列之触摸事件
- IOS之触摸事件
- ios之触摸事件
- iOS之触摸事件
- UI基础之----触摸事件
- iOS开发 UI 触摸手势
- ios事件之触摸事件
- IOS学习之——触摸事件处理
- IOS开发:手势触摸事件
- iOS开发之UI篇(1)—— UIView
- iOS开发之UI篇(2)—— UIImageView
- Storm架构基础之ApacheStorm计算模型详解与实战
- ImportError: No module named matplotlib.pyplot
- HDU 1102 Constructing Roads (最小生成树 Prim算法)
- 27.开源项目--git恢复已删除分支的提交
- HDOJ2111 Saving HDU(背包问题)
- iOS开发之UI篇(4)—— 触摸事件
- Jzoj4743 积木
- 搜索算法
- JDBC简单工作原理
- 51单片机实验 2017年11月22日
- HDU 1671 Phone List(字典树)
- Maven, HelloWorld, Java, Hadoop
- ABAP 对内表数据下载到EXCEL的几种方法
- 剑指offer---实现Singleton模式(2)