UI高级03-触摸事件 摇一摇 部分手势 控件不响应处理

摇一摇的相关事件, 都是从UIResponder中继承过来的

- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event
{
    NSLog(@"开始摇一摇");
}
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event
{
   NSLog(@"结束摇一摇");
}
- (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event
{
    // 如来电
    NSLog(@"摇一摇被取消");
}

触摸开始, 手指按下去 (没有松开)
在一次手势触摸的过程(从按下到松开), 只执行一次

- (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

获取当前的触摸点

UITouch *touch = [touches anyObject];

获取当前触摸的点在self.view上的位置 如果移动也会一直变动

CGPoint point = [touch locationInView:self.view];

获取触摸屏幕时记录的点 只记录触摸的一瞬间

CGPoint prePoint = [touch previousLocationInView:self.view];

视图默认只支持一个点的, 如果要支持多点的触摸, 需要额外配置 添加以下代码

 [self.view setMultipleTouchEnabled:YES];

示例:

以下方法实现后 添加视图素材 可以实现触摸屏幕的同时 触摸的地方显示素材光点

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
NSArray *touchArr = [touches allObjects];
    
    for (UITouch *touch in touchArr) {
        // -------- 2. 获取该获取点在根视图上的位置 --------
        CGPoint point = [touch locationInView:self.view];
        NSLog(@"%@", NSStringFromCGPoint(point));

        // -------- 3. 添加UIImage控件 --------
        UIImage *image = [UIImage imageNamed:@"spark_green"];
        UIImageView *imageview = [[UIImageView alloc] initWithImage:image];
        imageview.center = point;
        [self.view addSubview:imageview];

        // -------- 4. 逐渐消失的动画, 动画完之后移除 --------
        [UIView animateWithDuration:2.0 animations:^{
            imageview.alpha = 0.0;
        } completion:^(BOOL finished) {
            [imageview removeFromSuperview];
        }];
    }

遍历集合数据类型中的每个元素

     stop是BOOL *类型, 表示的是指向BOOL类型值的指针
   [touches enumerateObjectsUsingBlock:^(UITouch *obj, BOOL* stop) {
        // 每一次Block的执行, 都是集合中某一个元素的遍历操作
        NSLog(@"helloWord: %@", obj);
        
        // 当你找到需要的那个对象时, stop可以让遍历操作停下来
        // 将stop所指向的那个BOOL类型的值改成YES
        * stop = YES;
    }];
}

控件不响应的情况

  1. 控件的用户交互被关闭, 无法响应事件
    • setUserInteractionEnabled
    • 如果父视图不能响应事件, 子控件也不能响应事件
    • 响应者链条在父控件上断开
  2. 控件看不见时, 不能响应事件
    • 被隐藏, hidden
    • 透明度太小, <=0.01 (太透明, 跟没有一样)
  3. 触摸的点不在控件的有限范围之内
    • 子控件如果超出了父控件的范围, 那部分就不属于子控件的有限范围
    • 当超出部分没有被裁剪时, 会看得到超出的那部分范围, 但是它不会响应事件

超出父控件部分要裁剪

self.view.clipsToBounds = YES;

多点触摸:

  1. 视图默认支持1个点, 要启用多点支持, 额外配置
[self.view setMultipleTouchEnabled:YES];
  1. 集合的遍历, anyObject是任意的一个对象
    • 取出全部的集合对象 allObjects
    • 使用block遍历的方式 (数组, 字典, 集合)

** 响应事件触发时的调用堆栈**

  1. 运行循环 (检测整个应用的触摸事件) (死循环)
  2. 向UIApplication发送消息
  3. UIApplication向UIWindow (keyWindow)发送消息
  4. 依据响应者链条, 递归的让所有子视图都检测 (找出最终响应该事件的控件)
    • 如果找到了, 最终会传递回UIApplication, 再来执行相关的事件调用
    • 如果找不到, 最终也会传递回UIApplication, 由于没有控件能响应, 本次触摸结束

** 响应者链条**

  1. UIWindow 向下级传递, window的根控制器, 它的根视图
    • 如果下级视图, 是某个控制器的根视图, 会先传递给控制器, 再由控制器传递给根视图
  2. 视图会先检查其子视图是否能够响应事件
    • 每个视图, 都会优先检查子视图是否能响应
    • 检查完所有子视图, 再检查

使用hitTest方法来进行链条的传递

  • hitTest的返回值
  • null本次的传递当中, 没有发现对应的控件
  • UIView实例, 意味着找到响应的控件, 逆着链条将结果传递回去
  • pointInside: withEvent:

传递响应连接的关键方法
返回值:

  • 如果没有在响应范围之内, 是null
  • 如果是当前视图的响应, 返回自己
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
UIView *view = [super hitTest:point withEvent:event];
    NSLog(@"红色视图 - : %@", view);
    
    return view;
};

该方法判断触摸点是否在本控件有限范围之内, 返回结果
hitTest默认是使用pointInSide来检测触摸点是否为本控件来响应

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
BOOL result = [super pointInside:point withEvent:event];
    NSLog(@"%@", result ? @"触摸点在红色控件的范围之内" : @"不在范围内");
    
    return result;
};

手势

UIImageView的坑点
UIImageView默认不支持用户交互, 手势不能用(触摸事件)
SB中有配置用户交互的选项
UIImageView在SB中当中, 是不给添加子视图

** UIGestureRecognizer 是所有具体手势的抽象类**
手势在SB|Xib当中都提供了对应的控件
可以拖拽使用, 手势是针对控件而言, 往哪个控件身上拖拽, 就是向哪个控件添加手势
可以直接在SB当中, 为手势添加对应的响应事件
一个控件是可以同时添加多个手势, 各自响应自己的事件

  1. 可以将两个手势同时添加到一个控件里
    • 控件可以响应两个手势, 单独响应
  2. 允许两个手势同时响应 (默认不能允许)
    • 在一次触摸事件的过程当中, 两个手势是可以同时来响应
    • 通过UIGestureRecognizerDelegate方法来帮助实现

以下是部分手势添加示例 但是要手势有反应 需要实现方法(为手势添加方法)

捏合手势

Pinch 捏合手势 (放大缩小) UIPinchGestureRecognizer

  1. 实例化手势, 绑定触发的事件
UIPinchGestureRecognizer *pinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinchGestureAction:)];
    pinchGesture.delegate = self;
  1. 将手势添加到某个视图当中
[self.imageView addGestureRecognizer:pinchGesture];

撮合手势的响应事件件(就是添加的方法 上面只是添加了手势 但是手势之后会怎样响应需要自行实现)
需要两个触摸点, 多点触摸的支持 (视图默认只支持一个点)
如果不能使用, 就打开多点触摸的配置
** 该响应事件会触发多次, (多个阶段)**

-(void)pinchGestureAction:(UIPinchGestureRecognizer *)sender
{
   // scale 缩放比例 (两个点之间的距离变化)
   NSLog(@"%f, %zd", sender.scale, sender.numberOfTouches);
   
   // -------- 让图片跟随捏合进行放大缩小 --------
   // 1. 获取到缩放值
   // 2. 利用Transform来进行放大缩小
   self.imageView.transform = CGAffineTransformScale(sender.view.transform, sender.scale, sender.scale);
   
   // 重围scale初始计算值
   sender.scale = 1.0;
}

旋转手势

UIRotationGestureRecognizer *rotationGesture = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(rotationGestureAction:)];
    rotationGesture.delegate = self;
[self.imageView addGestureRecognizer:rotationGesture];

旋转手势的响应事件(就是添加的方法 上面只是添加了手势 但是手势之后会怎样响应需要自行实现)

- (void)rotationGestureAction:(UIRotationGestureRecognizer *)sender
{
    // 旋转的值的大小, 是弧度值
    NSLog(@"%f", sender.rotation);
    
    // 应用旋转
    sender.view.transform = CGAffineTransformRotate(sender.view.transform, sender.rotation);
    
    // 重置旋转的值的初始计算
    sender.rotation = 0;
}

如果需要同时响应多个手势事件 需要实现以下方法 并遵守UIGestureRecognizerDelegate协议

返回是否允许多个手势识别器同时识别各自的事件

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
    return YES;
}

你可能感兴趣的:(UI高级03-触摸事件 摇一摇 部分手势 控件不响应处理)