一、UIView的触摸事件
1、UIView的拖拽
- 创建一个view,用手指拖拽该view在屏幕的不同位置
#import "RedView.h"
@implementation RedView
//当开始触摸是自动调用
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
NSLog(@"%s",__func__);
}
//当触摸移动时调用
//NSArray:集合里面存入的元素都是有序的
//NSArray:集合里面存入的元素都是无序的
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
NSLog(@"%s",__func__);
//获取UITouch对象
UITouch *touch = [touches anyObject];
//上一个点:prePoint
//当前点:curPoint
//获取上一点
CGPoint preP = [touch previousLocationInView:self];
//获取当前点
CGPoint cur = [touch locationInView:self];
NSLog(@"preP = %@",NSStringFromCGPoint(preP));
NSLog(@"cur = %@",NSStringFromCGPoint(cur));
//x偏移量 = 当前点.x – 上一个点的.x
CGFloat offsetX = cur.x - preP.x;
//y偏移量 = 当前点.y – 上一个点的.y
CGFloat offsetY = cur.y - preP.y;
//让当前View跟着手指移动
//Transform->平移
self.transform = CGAffineTransformTranslate(self.transform, offsetX, offsetY);
}
//当手指离开时调用
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
NSLog(@"%s",__func__);
}
//当系统事件打断当前的触摸事件时调用
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
}
@end
2、事件的产生和传递
#import "WhiteView.h"
@implementation WhiteView
//5.找到后调用touchesBegan:方法
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
NSLog(@"%@----touch",[self class]);
}
//什么时候调用:当事件传递给当前View时, 会调用当前Veiw的hitTest方法.
//作用:寻找最适合的View.
//返回值:返回谁,谁就是最适合的view,谁就响应事件,就会调用谁的touches方法
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
//1.判断自己能否接收事件
//2.点在不在自己身上(通过调用下面的pointInside:方法)
//3.从后往前遍历自己了的子控件,把事件传递给子控件,调用子控件的hitTest,
//4.如果子控件没有找到最适合的View,那么自己就是最适合的View.
return [super hitTest:point withEvent:event];
}
//作用:点在不在自己身上,调用当前View一个方法(pointInside:)
//什么时候调用:在hitTest内部调用的
//返回值:YES在当前View身上, NO,不在
//point:当前触摸点
//注意:必须得要跟方法调用者在同一个坐标系
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
return YES;
}
@end
#import "XMGWindow.h"
@implementation XMGWindow
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
//1.判断自己能否接收事件
if (self.userInteractionEnabled == NO || self.hidden == YES || self.alpha <= 0.01) {
//不能接收事件
return nil;
}
//2.点在不在自己身上
if (![self pointInside:point withEvent:event]) {
return nil;
}
//3.从后往前遍历自己的子控件,把事件传递给子控件,调用子控件的hitTest,
int count = (int)self.subviews.count;
for (int i = count - 1; i >= 0; i--) {
//获取子控件
UIView *childView = self.subviews[i];
//把当前点的坐标系转换成子控件的坐标系
CGPoint childP = [self convertPoint:point toView:childView];
UIView *fitView = [childView hitTest:childP withEvent:event];
if (fitView) {
return fitView;
}
}
//4.如果子控件没有找到最适合的View,那么自己就是最适合的View.
return self;
}
@end
#import "YellorView.h"
@interface YellorView ()
@property (nonatomic,weak) IBOutlet UIButton *redBtn;
@end
@implementation YellorView
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
//判断点在不在红色按钮身上, 如果在,直接返回红色按钮
CGPoint redP = [self convertPoint:point toView:self.redBtn];
if ([self.redBtn pointInside:redP withEvent:event]) {
return self.redBtn;
}
//否则保持原有做法.
return [super hitTest:point withEvent:event];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
NSLog(@"%s",__func__);
}
3、事件响应(响应者链条)