#import "TouchView.h"
@implementation TouchView {
BOOL _isInside;
}
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {//创建的时候是传入的大小
//响应单点触摸,默认是YES
//self.userInteractionEnabled = NO;
//响应多点触摸,默认是NO
self.multipleTouchEnabled = YES;
//创建红色子视图
self.redView = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 50, 50)];
self.redView.backgroundColor = [UIColor redColor];
[self addSubview:self.redView];
//超出部分进行裁剪
self.clipsToBounds = YES;
}
return self;
}
//只有继承自UIResponder的类才能够复写这些方法来监听触摸事件
//触摸开始时调用此方法
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(@"触摸开始");
//判断是单点触摸还是多点触摸
// if (touches.count == 1) {
// NSLog(@"一根手指触摸");
// } else if (touches.count == 2) {
// NSLog(@"两根手指触摸");
// }
//UITouch的常用属性
UITouch *touch = [touches anyObject];
//1.window
// NSLog(@"%@", self.window);
// NSLog(@"%@", touch.window);
//
2.view
// NSLog(@"%@", touch.view);
// NSLog(@"%@", self);
// 3.tapCount
NSInteger count = touch.tapCount;
if (count == 1) {
[self performSelector:@selector(singleTap) withObject:nil afterDelay:0.3];
} else if (count == 2) {
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(singleTap) object:nil];//取消先前的做的请求
[self doubleTap];
}
//获取当前触摸点在视图上的坐标,slef是灰色视图,然后是根据灰色视图来确定坐标的
CGPoint p = [touch locationInView:self];
NSLog(@"p=%@", NSStringFromCGPoint(p));
//把self中的p点坐标转化为toView(redView)的坐标。
CGPoint p2 = [self convertPoint:p toView:self.redView];//眼里只有红色视图,那么点击P的坐标自然清楚,将点击点的坐标转换成红色视图的坐标
NSLog(@"p2=%j@", NSStringFromCGPoint(p2));//将坐标转换成string。
CGPoint p3 = [self convertPoint:p toView:self.superview];
NSLog(@"p3=%@", NSStringFromCGPoint(p3));
//把fromView(self)上的坐标点转化为self.superView上的坐标
//convertPoint转变坐标
CGPoint p4 = [self.superview convertPoint:p fromView:self];//将self的坐标转换为父视图的坐标。
NSLog(@"p4=%@", NSStringFromCGPoint(p4));
//判断当前的点击点是否在某个视图范围内,首先要有点的位置,然后有这个图的位置
_isInside = [self.redView pointInside:p2 withEvent:event];
if (_isInside) {
[UIView animateWithDuration:0.3 animations:^{
self.redView.transform = CGAffineTransformMakeScale(1.3, 1.3);//形变放大
}];
}
}
//按住红色视图,图标放大1.3倍,红色视图随手指移动,抬起手指还原。
- (void)singleTap {
NSLog(@"单击");
}
- (void)doubleTap {
NSLog(@"双击");
}
//触摸点移动时调用此方法
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
//NSLog(@"触摸移动");
if (_isInside) {
UITouch *touch = [touches anyObject];
CGPoint currentP = [touch locationInView:self];//移动后的坐标
CGPoint previousP = [touch previousLocationInView:self];//移动前的坐标
//移动距离
CGFloat moveX = currentP.x - previousP.x;
CGFloat moveY = currentP.y - previousP.y;
//设置redView的frame
CGRect frame = self.redView.frame;//子视图的frame值
frame.origin.x += moveX;
frame.origin.y += moveY;
self.redView.frame = frame;
}
}
//触摸结束时调用
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
[UIView animateWithDuration:0.3 animations:^{
self.redView.transform = CGAffineTransformIdentity;//表示返回图形原象
}];
}
//被其它事件取消时调用
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
[UIView animateWithDuration:0.3 animations:^{
self.redView.transform = CGAffineTransformIdentity;
}];
}
------------------------事件的分化传递------------------------------------
事件的分化传递:接受的是触摸的那个视图如果不接受则由其父视图或者controller接受。
#import "RootView.h"
#import "RedView.h"
#import "GreenView.h"
@implementation RootView
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
RedView *rdView = [[RedView alloc] initWithFrame:CGRectMake(20, 40, 100, 100)];
rdView.backgroundColor = [UIColor redColor];
[self addSubview:rdView];
GreenView *greenView = [[GreenView alloc] initWithFrame:CGRectMake(150, -40, 100, 100)];
greenView.backgroundColor = [UIColor greenColor];
[self addSubview:greenView];
}
return self;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(@"%@接收到事件", [self class]);//当前类的名字
}
还原hitTest:withEvent这个方法进行事件分发传递的过程
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
for (UIView *subView in self.subviews) {
//坐标系的转换,以上面的各个子视图为坐标原点,然后得出各个坐标,convertPoint是点击的坐标
CGPoint subViewPoint = [self convertPoint:point toView:subView];
//得到的是相对于子视图,点击坐标的位置
//判断是否在子视图范围内,因为坐标是以各个子视图为原点的,然后判断这个子视图是否在这个坐标里面,因为它是以子视图为原点的
BOOL result = [subView pointInside:subViewPoint withEvent:event];
if (result) {
//判断一些属性的值,来确定是否把事件分发到subView。
if (!subView.userInteractionEnabled) {//userInteractionEnabled该属性决定是否接受用户交互
return [super hitTest:point withEvent:event];
}
return subView;
}
}
return [super hitTest:point withEvent:event];
}