zoukankan      html  css  js  c++  java
  • iOS手势 规避同一界面上不同子界面同时响应多个手势

    最近在项目中遇到这样一个有关iOS手势的问题,首先需求描述如下:在一个CollectionView中,要求长按不同的cell,产生一个cell的snapshot,此时可拖拽这个snapshot再进行后续的操作(如拖到view的某个位置出发一个事件)”。需求本身并不复杂,但要求每次只能有一个cell响应长按手势,不允许同时有两个或以上的cell响应长按手势。

    我们知道UIGestureRecognizer有很多回调和方法可以兼容同一个View上的多种手势,网上相关的教程也很多,比如:

    http://coder.aqualuna.me/2011/07/uigesturerecognizer.html

    也有这种很全面的流水式教程:

    http://blog.csdn.net/namehzf/article/details/7424882

    但是都没有解决我的问题的方案,因为我研究的是多个subview上的手势共存问题,不是单个view上不同手势共存问题。于是求人不如求自己,自己动手解决吧。(为此我做了个简化的demo放在这里https://github.com/pigpigdaddy/LongPressSingleDemo,供读者下载斧正)

    思路有两条:

    1,将长按手势加在collectionView上,通过手势在collectionView上的位置point,获取此位置的cell(如果有)。优势:代码量少,逻辑简单。劣势:两个cell同时长按时,任何一个长按操作都无法识别!

    相关代码:

    1 - (void)longPressAction:(UILongPressGestureRecognizer *)ges
    2 {
    3     if (ges.state == UIGestureRecognizerStateBegan) {
    4         CGPoint point = [ges locationInView:self.collectionView];
    5         NSIndexPath *indexPath = [self.collectionView indexPathForItemAtPoint:point];
    6         NSLog(@"%@==%d==%d",indexPath, indexPath.section, indexPath.row);
    7     }
    8 }

    既然思路1无法实现我的需求,那么我就不就此展开讨论,demo代码中也没有体现,不过这种思路或许可以适用于其它需求。

    2,将长按手势加在collectionViewCell上,长按响应后,以delegate回调的形式,将所长按cell的location、cell的index等相关属性上传到上层,再进行相关后续操作。优势:可以同时响应一个或者多个cell的长按。劣势:多个cell同时响应,无法满足我项目的需求。于是,如何解决呢?这才是这篇文章的关键。

    UIGestureRecognizer的回调中,有一个最基本的:

     1 - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
     2 {
     3     return YES;
    4 }

    默认返回YES。那么,如果我在当前cell响应了长按事件后,将这里设置为NO,那么接下来的cell就不在响应长按事件了。另外,当前cell的长按结束后,再将这里设置为YES,后续的cell就又能正常响应自己的长按事件了。

    于是,我创建了一个单例,专门用于控制全局的长按事件,之所以做成单例,而不在cell的上层view来记录长按状态,因为考虑到项目之间的通用性,以后项目如果需要这样的需求,可以直接引用这个单例类。

    OK,下面是我的单例的接口文件:

     1 //
     2 //  LongPressControl.h
     3 //  Classroom
     4 //
     5 //  Created by pigpigdaddy on 14-3-24.
     6 //  Copyright (c) 2014年 pigpigdaddy. All rights reserved.
     7 //
     8 //  某些界面上可能会有多个子界面,这些子界面都有自己的长按事件,如果你不想让这些长按事件先后都触发
     9 //  可以使用本类加以控制
    10 
    11 //  2014-04-08 增加区分手势调用
    12 
    13 typedef enum {
    14     LONG_PRESS_VIEW_DEMO = 1,         
    15 }LONG_PRESS_VIEW;
    16 
    17 #import <Foundation/Foundation.h>
    18 
    19 @interface LongPressControl : NSObject
    20 {
    21     NSMutableArray *_arrayLongPressView;
    22 }
    23 
    24 #pragma mark
    25 #pragma mark-------------创建 销毁---------------------
    26 /**   函数名称 :shareInfo
    27  **   函数作用 :创建 LongPressControl 单例对象
    28  **   函数参数 :
    29  **   函数返回值:URLog 单例对象
    30  **/
    31 +(LongPressControl *)shareInfo;
    32 
    33 /**   函数名称 :freeInfo
    34  **   函数作用 :释放 LongPressControl 单例对象
    35  **   函数参数 :
    36  **   函数返回值:
    37  **/
    38 +(void)freeInfo;
    39 
    40 /*!
    41  *  TODO:添加长按事件
    42  *
    43  *  @param view 调用的view
    44  *
    45  *  @author pigpigdaddy
    46  */
    47 - (void)addLongPressAction:(LONG_PRESS_VIEW)view;
    48 
    49 /*!
    50  *  TODO:删除长按事件
    51  *
    52  *  @param view 调用的view
    53  *
    54  *  @author pigpigdaddy
    55  */
    56 - (void)removeLongPressAction:(LONG_PRESS_VIEW)view;
    57 
    58 /*!
    59  *  TODO:是否存在长按事件
    60  *
    61  *  @param view 是那个View
    62  *
    63  *  @return
    64  *
    65  *  @author pigpigdaddy
    66  */
    67 - (BOOL)isExistLongPressAction:(LONG_PRESS_VIEW)view;
    68 
    69 @end

    LONG_PRESS_VIEW这个Type,用于记录并区分当前是哪个view需要这样的控制,比如这个demo中就是LONG_PRESS_VIEW_DEMO,以后可以在类型中添加新的type。

    _arrayLongPressView用于将Type类型添加进来,如果cell手势响应,就添加相应view的type进来。

    三个函数,分别在cell开始手势时添加type、cell结束手势时移除type、以及判断当前view是否已经有cell正在被响应手势。

    这样,这个单例就像是一把锁,一旦手势进入就上锁,直到手势结束才打开锁。

    来看一下我实际的democell的实现文件,如何处理手势

     1 - (void)longPressAction:(UILongPressGestureRecognizer *)ges
     2 {
     3     switch (ges.state) {
     4         case UIGestureRecognizerStateBegan:{
     5             NSLog(@"%@",[NSString stringWithFormat:@"%d===%d", self.indexPath.section, self.indexPath.row]);
     6         }
     7             break;
     8         case UIGestureRecognizerStateChanged:{
     9             
    10         }
    11             break;
    12         case UIGestureRecognizerStateEnded:{
    13             [[LongPressControl shareInfo] removeLongPressAction:LONG_PRESS_VIEW_DEMO];
    14         }
    15             break;
    16         case UIGestureRecognizerStateCancelled:{
    17             [[LongPressControl shareInfo] removeLongPressAction:LONG_PRESS_VIEW_DEMO];
    18         }
    19             break;
    20         case UIGestureRecognizerStateFailed:{
    21             [[LongPressControl shareInfo] removeLongPressAction:LONG_PRESS_VIEW_DEMO];
    22         }
    23             break;
    24             
    25         default:
    26             break;
    27     }
    28 }
    29 
    30 - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
    31 {
    32     if (gestureRecognizer != self.longPressGes) {
    33         return NO;
    34     }else if ([[LongPressControl shareInfo] isExistLongPressAction:LONG_PRESS_VIEW_DEMO]){
    35         return NO;
    36     }else{
    37         [[LongPressControl shareInfo] addLongPressAction:LONG_PRESS_VIEW_DEMO];
    38         return YES;
    39     }
    40 }

    如此,我的collectionView中的多个cell,不再同时响应多个cell的手势,而且同时长按时,也只有第一个cell会响应长按手势。工作良好!

    请参考demo(这里https://github.com/pigpigdaddy/LongPressSingleDemo

    另外,我遇到一个问题,就是

    - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer 函数每次进入的时候,都会有一个仿佛“collectionViewCell自带的长按手势(_handleGestureRecognizer)”会进入,我参看了UICollectionViewCell的.h文件,其中声明了@class UILongPressGestureRecognizer;但并没有发现有任何关于手势的接口,很奇怪,是iOS的保留节目吗?有知道的可以帮忙解释一下吗?感谢!

  • 相关阅读:
    MySQL
    Shell运算符:Shell算数运算符、关系运算符、布尔运算符、字符串运算符等
    ps
    top
    sed
    nav响应范围一定要足够宽
    续上获取input的checked用prop时返回的是布尔值
    jq不应该用attr获取input的check值
    jq祖级元素
    一些jquery的坑
  • 原文地址:https://www.cnblogs.com/pigpigDD/p/3895231.html
Copyright © 2011-2022 走看看