1、UITouch
UITouch的属性
//触摸产生时所处的窗口
@property (nonatomic , readonly, retain) UIWindow *window;
//触摸产生时所处的视图
@property (nonatomic , readonly, retain)UIView *view;
//短时间内点按屏幕的次数,可以根据tapCount判断单击、双击或更多的点击
@property (nonatomic , readonly) NSUInteger tapCount ;
//记录了触摸事件产生或变化时的时间,单位是秒
@property (nonatomic, readonly) NSTimeInterval timestamp ;
//当前触摸事件所处的状态
@property (nonatomic, readonly) UITouchPhase phase;
UITouch的方法
//返回值表示触摸在view上的位置
//这里返回的位置是针对view的坐标系的(以view的左上角为原点[0, 0])
//调用时传入的view参数为nil的话,返回的是触摸点在UIWindow的位置
- (CGPoint) locationInView: (UIView *)view;
//该方法记录了前一个触摸点的位置
- (CGPoint) previousLocationInView: (UIView *)view;
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
// 获取当前点
CGPoint currentPoint = [touch locationInView:self];
//获取上一个点
CGPoint previousPoint = [touch previousLocationInView:self];
//获取XY轴偏移量
CGFloat offsetX = currentPoint.x - previousPoint.x;
CGFloat offsetY = currentPoint.y - previousPoint.y;
//修改View的位置(frame,center,transform)
//从当期位置计算偏移量
self.transform = CGAffineTransformTranslate(self.transform, offsetX, offsetY);
//每次都是从0计算偏移量
// self.transform = CGAffineTransformMakeTranslation(offsetX, offsetY);
}
注意:即使用多跟手指同时拖动一个View,也只为产生一个UITouch对象,通过更改self.multipleTouchEnabled属性可以实现产生多个UITouch对象,但是不建议这么做。
响应者对象UIResponder
- 在iOS中不是任何对象都能处理事件,只有继承了UIResponder的对象才能接收并处理事件。我们称之为“响应者对象”
- UIApplication、UIViewController、UIView都继承自UIResponder,因此它们都是响应者对象,都能够接收并处理事件
UIResponder内部提供了以下方法来处理事件
触摸事件
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;
加速计事件
- (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;
UIEvent
每产生一个事件,就会产生一个UIEvent对象
UIEvent:称为事件对象,记录事件产生的时刻和类型
常见属性
事件类型
@property(nonatomic,readonly) UIEventType type;
@property(nonatomic,readonly) UIEventSubtype subtype;
事件产生的时间
@property(nonatomic,readonly) NSTimeInterval timestamp;
UIEvent还提供了相应的方法可以获得在某个view上面的触摸对象(UITouch)
typedef NS_ENUM(NSInteger, UIEventType) {
UIEventTypeTouches,
UIEventTypeMotion,
UIEventTypeRemoteControl,
};
typedef NS_ENUM(NSInteger, UIEventSubtype) {
// available in iPhone OS 3.0
UIEventSubtypeNone = 0,
// for UIEventTypeMotion, available in iPhone OS 3.0
UIEventSubtypeMotionShake = 1,
// for UIEventTypeRemoteControl, available in iOS 4.0
UIEventSubtypeRemoteControlPlay = 100,
UIEventSubtypeRemoteControlPause = 101,
UIEventSubtypeRemoteControlStop = 102,
UIEventSubtypeRemoteControlTogglePlayPause = 103,
UIEventSubtypeRemoteControlNextTrack = 104,
UIEventSubtypeRemoteControlPreviousTrack = 105,
UIEventSubtypeRemoteControlBeginSeekingBackward = 106,
UIEventSubtypeRemoteControlEndSeekingBackward = 107,
UIEventSubtypeRemoteControlBeginSeekingForward = 108,
UIEventSubtypeRemoteControlEndSeekingForward = 109,
};
HitTest
HitTest练习如下:
// hitTest:withEvent:作用:就是用来寻找最合适的view
//什么时候调用:当一个事件传递给当前View的时候调用
//返回值:返回是谁,谁就是最适合的view,就会调用该view的touch方法
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
// 当前控件上的点转换到chatView上
CGPoint chatP = [self convertPoint:point toView:self.chatView];
// 判断下点在不在chatView上
if ([self.chatView pointInside:chatP withEvent:event]) {
return self.chatView;
}else{
return [super hitTest:point withEvent:event];
}
}
//作用:寻找最适全的View
//参数:point 当前手指的点. event当前的事件.
//什么时候调用:当一个事件传递给当前View的时候就会调用.
-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
// return [super hitTest:point withEvent:event];
//1.判断自己能否接收事件
if(self.userInteractionEnabled == NO || self.hidden == YES || self.alpha <= 0.01){
return nil;
}
//2.触摸点在不在当前的View.
if (![self pointInside:point withEvent:event]) {
return nil;
}
//3.从后往前遍历出自己的子控件.重复前两步操作,看自己子控件是不是最适合的Viwe.
int count = (int)self.subviews.count;
for (int i = count -1; i >= 0; i--) {
UIView *childV = self.subviews[i];
//把当前的点转换成childV坐标系的点.
CGPoint childPoint = [self convertPoint:point toView:childV];
//判断子控件是不是最适合的View.
UIView *fitView = [childV hitTest:childPoint withEvent:event];
if (fitView) {
return fitView;
}
}
//4.如果没有符合条件的子控件,那么它自己就是这个最适合的View.
return self;
}
//hitTest底层会调用pointInside.
//判断当前点在不在当前的view上.
//point点必须是跟当前View同一坐标系的点.
-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event{
return YES;
}