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

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

作者: xwf_code | 来源:发表于2016-10-18 21:18 被阅读0次

    摇一摇的相关事件, 都是从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<UITouch *> *)touches withEvent:(UIEvent *)event
    

    触摸后开始移动, 手指按下后还没有松开, 然后开始移动 (手指还没有离开屏幕)
    在一次手势触摸的过程(从按下到松开), 会执行很多次

    - (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
    

    触摸结束, 手指离开了屏幕了

    - (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
    

    触摸取消, 如来电

    - (void)touchesCancelled:(NSSet<UITouch *> *)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<UITouch *> *)touches withEvent:(UIEvent *)event
    {
    NSArray<UITouch *> *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-触摸事件 摇一摇 部分手势 控件不响应处理

          本文链接:https://www.haomeiwen.com/subject/vymtuttx.html