UITouch相关:
3大事件:触摸事件,加速计事件,远程控制事件
响应者对象:只有继承了UIResponser的对象才能接收并处理事件
UIResponser内部提供以下方法处理事件:
触摸事件(UIView)
一根或者多根手指开始触摸view,系统会自动调用view的下面方法
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
一根或者多根手指在view上移动,系统会自动调用view的下面方法(随着手指的移动,会持续调用该方法)
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
一根或者多根手指离开view,系统会自动调用view的下面方法
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
触摸结束前,某个系统事件(例如电话呼入)会打断触摸过程,系统会自动调用view的下面方法
(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
提示:touches中存放的都是UITouch对象
加速计事件
- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event;
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event;
- (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event;
远程控制事件
- (void)remoteControlReceivedWithEvent:(UIEvent *)event;
UITouch:
当用户用一根手指触摸屏幕时,会创建一个与手指相关联的UITouch对象
一根手指对应一个UITouch对象
UITouch的作用
保存着跟手指相关的信息,比如触摸的位置、时间、阶段
当手指移动时,系统会更新同一个UITouch对象,使之能够一直保存该手指的触摸位置。
当手指离开屏幕时,系统会销毁相应的UITouch对象
View的拖拽:
// 一个完整的触摸过程
// touchesBegan -> touchesMoved -> touchesEnded
/*
NSArray 集合 有序
NSSet 无序
*/
// 触摸开始
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
// 获取一个UITouch
UITouch *touch = [touches anyObject];
// NSLog(@"%s----%d",__func__,touches.count);//多根手指
// NSLog(@"%d",touch.tapCount);//短时间内点击的次数,可以判断当前用户是单击还是双击
// NSLog(@"%d",touch.phase);//<span style="color:#595959;">当前触摸事件所处的状态</span><span style="color:#4F81BD;">,</span>可以判断当前手指就按下,移动,还是抬起
}
// 手指移动
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
// 获取一个UITouch
UITouch *touch = [touches anyObject];
//[touch locationInView:view ] 获取
// 获取当前的位置
CGPoint current = [touch locationInView:self];
// 获取上一个点
CGPoint pre = [touch previousLocationInView:self];
// x轴偏移量
CGFloat offsetX = current.x - pre.x;
CGFloat offsetY = current.y - pre.y;
NSLog(@"%@",NSStringFromCGPoint(current));
// 获取视图的center
CGPoint center = self.center;
center.x += offsetX;
center.y += offsetY;
self.center = center;
}
// 触摸结束
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
// 获取一个UITouch
UITouch *touch = [touches anyObject];
// NSLog(@"%d",touch.phase);
// NSLog(@"%s----%p",__func__,touch);
}
// 触摸被打断 比如打电话过来
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
}
UITouch中常用方法:
<pre name="code" class="objc">- (CGPoint)locationInView:(UIView *)view;
返回值表示触摸在view上的位置
这里返回的位置是针对<span style="color:#FF0000;">view</span>的坐标系的(以view的左上角为原点(0, 0))
调用时传入的view参数为nil的话,返回的是触摸点在UIWindow的位置
- (CGPoint)previousLocationInView:(UIView *)view;
该方法记录了前一个触摸点的位置
事件的产生和传递:
发生触摸事件后,系统会将该事件加入到一个由
UIApplication
管理的事件
队列(先产生先处理)
中
UIApplication
会从事件队列中
取出最前面的
事件,并将事件分发下去以便处
理,通常,先发送事件给应用程序的主窗
口(
keyWindow
)
主窗口会在视图层次结构中
找到一个最合适的视图来处理触摸事件
,但是这仅仅是整个事件处理过程的第一步
找到合适的视图控件后,就会调用视图控件的
touches
方法来作具体的事件处理•
触摸事件的传递是从父控件传递到子控件
触摸事件的监听:
点击了绿色的
view
:
UIApplication->UIWindow-> 白色->绿色
点击了蓝色的
view
:
UIApplication->UIWindow-> 白色->橙色-> 蓝色
点击了黄色的
view
:
UIApplication->UIWindow-> 白色->橙色-> 蓝色->黄色
如果父控件不能接收触摸事件,那么子控件就不可能接收到触摸
事件
(
掌握
)
如何找到最合适的控件来处理事件?
1>
自己是否能接收触摸事件?否,事件传递到此结束
2>
触摸点是否在自己身上?否,事件传递到此结束
3>
从后往前遍历子控件(需要递归的遍历子控件,看子控件能否处理),重复前面的两个步骤
4>
如果没有符合条件的子控件,那么就自己最适合处理
UIView不接收事件三种情况:
1.
不接收用户交互
userInteractionEnabled =NO
2.
隐藏
hidden = YES
3.
透明
alpha = 0.0~0.01
提示:UIImageView的userInteractionEnabled默认就是NO,因此UIImageView以及它的子控件默认是不能接收触摸事件的
hitTest方法的原理:UIApplication sharedApplication].keyWindow hitTest:CGPoint withEvent:(UIEvent *)hitTest:wihtEvent1,看窗口能否接收,如果不能retrun nil;自己不能接收事件,也不能处理事件,而且也不能把事件传递给子控件2,判断点在不在窗口上 ,如果点在窗口上,意味着窗口满足是合适的view3,白色的view如果想监听一个view上面的触摸事件,之前的做法是
自定义一个view
实现view的touches方法,在方法内部实现具体处理代码
通过touches方法监听view触摸事件,有很明显的几个缺点
必须得自定义view
由于是在view内部的touches方法中监听触摸事件,因此默认情况下,无法让其他外界对象监听view的触摸事件
不容易区分用户的具体手势行为
iOS 3.2之后,苹果推出了手势识别功能(Gesture Recognizer),在触摸事件处理方面,大大简化了开发者的开发难度
手势识别:
为了完成手势识别,必须借助于手势识别器----UIGestureRecognizer
利用UIGestureRecognizer,能轻松识别用户在某个view上面做的一些常见手势
UIGestureRecognizer是一个抽象类,定义了所有手势的基本行为,使用它的子类才能处理具体的手势
UITapGestureRecognizer(敲击)
UIPinchGestureRecognizer(捏合,用于缩放)
UIPanGestureRecognizer(拖拽)
UISwipeGestureRecognizer(轻扫)
UIRotationGestureRecognizer(旋转)
UILongPressGestureRecognizer(长按)
每一个手势识别器的用法都差不多,比如UITapGestureRecognizer的使用步骤如下
创建手势识别器对象
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] init];
设置手势识别器对象的具体属性
// 连续敲击2次
tap.numberOfTapsRequired = 2;
// 需要2根手指一起敲击
tap.numberOfTouchesRequired = 2;
添加手势识别器到对应的view上
[self.iconView addGestureRecognizer:tap];
监听手势的触发
[tap addTarget:self action:@selector(tapIconView:)];
手势识别的状态:
typedef NS_ENUM(NSInteger, UIGestureRecognizerState) {
// 没有触摸事件发生,所有手势识别的默认状态
UIGestureRecognizerStatePossible,
// 一个手势已经开始但尚未改变或者完成时
UIGestureRecognizerStateBegan,
// 手势状态改变
UIGestureRecognizerStateChanged,
// 手势完成
UIGestureRecognizerStateEnded,
// 手势取消,恢复至Possible状态
UIGestureRecognizerStateCancelled,
// 手势失败,恢复至Possible状态
UIGestureRecognizerStateFailed,
// 识别到手势识别
UIGestureRecognizerStateRecognized = UIGestureRecognizerStateEnded
};
用法示例:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// pan
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)];
//UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tap:)];
//tap.numberOfTpasRequired=2;//点按多少次才能触发手势
//tap.numberOfTouchesRequired=2;//必须多少个手指触摸才能触发
[_imagView addGestureRecognizer:pan];
}
- (void)pan:(UIPanGestureRecognizer *)pan
{
// 获取手指移动的位置
CGPoint trans = [pan translationInView:_imagView];
_imagView.transform = CGAffineTransformTranslate(_imagView.transform, trans.x, trans.y);
// 复位
[pan setTranslation:CGPointZero inView:_imagView];
NSLog(@"%@",NSStringFromCGPoint(trans));
}
#warning pinch
- (void)addPinch
{
UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinch:)];
// 设置代理的原因:想要同时支持多个手势
pinch.delegate = self;
[_imagView addGestureRecognizer:pinch];
}
- (void)pinch:(UIPinchGestureRecognizer *)pinch
{
_imagView.transform = CGAffineTransformScale(_imagView.transform, pinch.scale, pinch.scale);
// 复位
pinch.scale = 1;
}
// Simultaneous:同时
// 默认是不支持多个手势
// 当你使用一个手势的时候就会调用
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}
#warning rotation
- (void)addRotation
{
// rotation
UIRotationGestureRecognizer *rotation = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(rotation:)];
rotation.delegate = self;
[_imagView addGestureRecognizer:rotation];
}
- (void)rotation:(UIRotationGestureRecognizer *)rotation
{
NSLog(@"%f",rotation.rotation);
// _imagView.transform = CGAffineTransformMakeRotation(rotation.rotation);
_imagView.transform = CGAffineTransformRotate(_imagView.transform, rotation.rotation);
// 复位
rotation.rotation = 0;
}
#warning Swipe
- (void)addSwipe
{
// Swipe
// 一个手势只能识别一个方向
UISwipeGestureRecognizer *swipe = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipe:)];
swipe.direction = UISwipeGestureRecognizerDirectionRight;
[_imagView addGestureRecognizer:swipe];
}
- (void)swipe:(UISwipeGestureRecognizer *)swipe
{
NSLog(@"swipe");
}
#warning longPress
- (void)addLongPress
{
// longPress
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPress:)];
[_imagView addGestureRecognizer:longPress];
}
- (void)longPress:(UILongPressGestureRecognizer *)longPress
{
// 根据状态执行事件
if (longPress.state == UIGestureRecognizerStateBegan) {
NSLog(@"longPress");
}
}
#warning tap
- (void)addTap
{
// tap
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tap:)];
// 点按多少次才能触发手势
// tap.numberOfTapsRequired = 2;
//
// // 必须多少个手指触摸才能触发手势
// tap.numberOfTouchesRequired = 2;
tap.delegate = self;
[_imagView addGestureRecognizer:tap];
}
// 这个触摸点能否触发手势
//- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
//{
// CGPoint currentPoint = [touch locationInView:_imagView];
//
// if (currentPoint.x < _imagView.bounds.size.width * 0.5) {
// return NO;
// }else{
//
// return YES;
// }
//}
- (void)tap:(UITapGestureRecognizer *)tap
{
NSLog(@"tap");
}