只有继承了UIResponder的对象才能接收并处理事件。我们称之为“响应者对象”
//一根或者多根手指开始触摸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
属性
//短时间内点按屏幕的次数,可以根据tapCount判断单击、双击或更多的点击
@property(nonatomic,readonly) NSUInteger tapCount;
//当前触摸事件所处的状态 (用于判断调用什么方法)
@property(nonatomic,readonly) UITouchPhase phase;
//触摸产生时所处的窗口
@property(nonatomic,readonly,retain) UIWindow *window;
//触摸产生时所处的视图
@property(nonatomic,readonly,retain) UIView *view;
方法
// 获取手指
UITouch *touch = [touches anyObject];
//返回值表示触摸在view上的位置
//这里返回的位置是针对view的坐标系的(以view的左上角为原点(0, 0))
//调用时传入的view参数为nil的话,返回的是触摸点在UIWindow的位置
- (CGPoint)locationInView:(UIView *)view;
//该方法记录了前一个触摸点的位置
- (CGPoint)previousLocationInView:(UIView *)view;
下面三种情况时视图会不接受触摸事件
1.不接收用户交互
userInteractionEnabled = NO
2.隐藏
hidden = YES
3.透明
alpha = 0.0 ~ 0.01
触摸事件底层的事件传递
//事件 -> UIApplication -> 窗口,让这个窗口去寻找最合适的View
底层会调用(返回的是最适合的响应视图)
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event;
这个底层会调用(返回YES为响应No为不响应)
-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event;
来返回最合适的View来响应事件
例1: 如图 按钮在黄色View下 怎么才能透过View点击按钮(除了上述三种不接受触摸事件的情况)
方法一: 重写黄色视图的hitTest方法
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
//这里经常会用到 UIView的转换坐标方法
// 把这个点的坐标系转换成按钮的坐标系
CGPoint btnP = [self convertPoint:point toView:self.btn];
// 判断这个点在不在按钮上面
if ([self.btn pointInside:btnP withEvent:event]) { // 点在按钮上
return self.btn;
}else{
return [super hitTest:point withEvent:event];
}
}
方法二: 重写
-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
CGPoint btnP = [self convertPoint:point toView:self.btn];
if ([self.btn pointInside:btnP withEvent:event]) {// 在按钮上
return NO;
}else{
return [super pointInside:point withEvent:event];
}
}
例2 当子控件超出父控件范围 则不响应事件
如下图 按钮是蓝色view’的子控件 则左右侧超出部分不响应按钮点击
解决方案 在左侧 在蓝色view里 重写hitTest方法 来返回如果点在按钮上 即使超出父控件也可以响应
UIGestureRecognizer手势识别器
使用前提 是视图 可以与用户交互例如UIImageView默认是不可交互需要设置
userInteractionEnabled = YES;
//手势识别器----UIGestureRecognizer是一个抽象类,定义了所有手势的基本行为,使用它的子类才能处理具体的手势
UITapGestureRecognizer(敲击)
UIPinchGestureRecognizer(捏合,用于缩放)
UIPanGestureRecognizer(拖拽)
UISwipeGestureRecognizer(轻扫)
UIRotationGestureRecognizer(旋转)
UILongPressGestureRecognizer(长按)
例:
//创建手势
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tapLabel:)];
//给Label添加手势
[label addGestureRecognizer:tap];
//让label可以交互
label.userInteractionEnabled = YES;
-(void)tapLabel:(UITapGestureRecognizer *)tap{
//如果多个Label可以通过tap.view.tag 来区分label
NSLog(@"%zd",tap.view.tag);
}
注意
// 对于UISwipeGestureRecognizer清扫手势默认是向右的 可以改下边属性来改变方向
@property(nonatomic) UISwipeGestureRecognizerDirection direction;
UISwipeGestureRecognizer *swipe = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(swipe:)];
// 默认向右
swipe.direction = UISwipeGestureRecognizerDirectionDown | UISwipeGestureRecognizerDirectionUp;
- (void)swipe:(UISwipeGestureRecognizer *)swipe
{
//可以通过这个判断 来对特定方向进行操作
if (swipe.direction == UISwipeGestureRecognizerDirectionUp) {
<#statements#>
}
}
//对于长按手势UILongPressGestureRecognizer
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc]initWithTarget:self action:@selector(longPress:)];
// 默认触发两次,通常需要做一个判断
- (void)longPress:(UILongPressGestureRecognizer *)longPress
{ //长按开始时
if(longPress.state == UIGestureRecognizerStateBegan){
NSLog(@"%s",__func__);
}
}
//关于旋转/拖拽/捏合手势
//在操作完之后要进行复位
如:rotation/pan/pinch 为三种手势对象
// 旋转复位(因为角度不复位会叠加/不是相对于上一次,相对于一开始)
rotation.rotation = 0;
// 捏合复位
pinch.scale = 1;
// 拖拽复位
[pan setTranslation:CGPointZero inView:self.imageView];
UIGestureRecognizerDelegate
// 是否允许接收触摸
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
return YES/NO; // 允许/不允许
}
// 当用户需要同时使用多个手势的时候就会调用
// 判断是否支持多个手势,YES,支持(默认为No)
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}
storyboard小发现
将Main.storyboard里的控件 连线到自定义view属性中
一般情况下 只能连线到控制器中
这边应该在自定义View中 先写好IBOutlet属性 进行反向连线
哈哈~这算不算黑魔法 算不算 算不算 算不算….