#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];
}