【问题标题】:Combining swipe down and long press结合向下滑动和长按
【发布时间】:2012-12-05 15:31:37
【问题描述】:

我试图在我的 ViewController(它有一个 tableView)中实现两个手势识别器,它们必须一个接一个地工作。第一个是向下滑动手势,第二个是长按手势。

这是我使用@sergio 建议修改的代码

    - (void)viewDidLoad
    {
        [super viewDidLoad];

        swipeDown = [[[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(swipeDownAction)] autorelease];

        longPress = [[[CustomLongPress alloc]initWithTarget:self action:@selector(longPressAction)] autorelease];


        longPress.minimumPressDuration = 2;

        swipeDown.numberOfTouchesRequired = 1;

        swipeDown.direction = UISwipeGestureRecognizerDirectionDown;


       swipeDown.delegate = self ;

        longPress.delegate = self ;

        [myTableView addGestureRecognizer:swipeDown];

        [myTableView addGestureRecognizer:longPress];





  }


    -(void)swipeDownAction {

        _methodHasBeenCalled = YES;    // bool @property declared in .h

        NSLog(@"Swipe down detected");


    }



    -(void)longPressAction {

        NSLog(@"long press detected");
    }

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

还有我的 UILongPressGestureRecognizer 子类:

#import "CustomLongPress.h"
#import "ViewController.h"


@interface CustomLongPress()
{

    ViewController *vc;
}

@end


@implementation CustomLongPress
-(id)initWithTarget:(id)target action:(SEL)action controller:(ViewController *)viewCon
{
    self = [super initWithTarget:target action:action];

    if (self) {

        vc = viewCon;

    }

    return self;
}


-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
     NSLog(vc.methodHasBeenCalled ? @"Yes" : @"No");

    if (vc.methodHasBeenCalled) {

        [super touchesBegan:touches withEvent:event];
    }
}

不幸的是,我仍然只能从 swipeDown 获得日志,但在 longPress 时没有日志

【问题讨论】:

    标签: ios uigesturerecognizer


    【解决方案1】:

    为此,您需要创建自己的自定义手势识别器。最好的方法是让您继承 UILongPressGestureRecognizer 并使其仅在滑动结束后“接受”长按。例如,在touchesBegan 方法中

    - (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {
       <if swipe recognizer action method has been called>
           [super touchesBegan:touches withEvent:event];
       }
    }
    

    这样,两个手势识别器都会尝试识别手势:滑动识别器会立即这样做;而自定义识别器会“等待”滑动识别器触发。

    实现条件&lt;if swipe recognizer action method has been called&gt; 的一种简单方法是在您的滑动操作中设置一个全局标志(您在执行滑动操作时设置它;然后自定义识别器读取它的值)。这简单,目前还不是你能找到的最好的实现。

    另一种方法是依靠 requiresGestureRecognizerToFail 链接 3 个标准手势识别器,我们称它们为 A、B 和 C,其中:

    1. A 是UISwipeGestureRecognizer;
    2. C 是UILongPressGestureRecognizer;
    3. B 是任何手势识别器。

    您可以这样配置它们:

    C --> B --> A
    

    其中x --&gt; y 表示x 要求y 失败。因此,您将拥有C(您的长按手势识别器)将要求B GR 失败,而B 需要A(您的滑动识别器)失败;只要A 识别到滑动,B 就会失败;一旦B 失败,C 将被允许识别长按。

    编辑:

    阅读您的评论后,您是否介意尝试一下,看看是否有帮助:

    1. 删除您覆盖的 touchesBegan 并将其替换为:

      - (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {
      }
      
    2. 然后定义:

      - (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event {
      
        if (vc.methodHasBeenCalled) {
          [super touchesBegan:touches withEvent:event];
        } else {
           return;
        }
      }
      

    如果这不起作用,则让您的自定义手势识别器继承自通用手势识别器并

    1. touchesBegan: 留在原处并将touchesMoved 替换为:

      - (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event {
      
        self.lastTouch = [touches anyObject];
        if (vc.methodHasBeenCalled && self.gestureNotBegunYet == YES) {
          self.gestureNotBegunYet = NO;
          [self performSelector:@selector(recognizeLongPress) withObject:nil afterDelay:1.0];
      
        } else {
           return;
        }
      }
      

    并添加:

    - (float)travelledDistance {
      CGPoint currentLocation = [self.lastTouch locationInView:self.view.superview];
      return sqrt(pow((currentLocation.x - self.initialLocation.x), 2.0) +
                pow((currentLocation.y - self.initialLocation.y), 2.0));
    }
    
    - (void)fail {
      self.gestureNotBegunYet = YES;
      [NSObject cancelPreviousPerformRequestsWithTarget:self];
    
    }
    
    - (void)recognizeLongPress {
    
      if ([self travelledDistance] < kTapDragThreshold) {
        self.longPressed = YES;
        self.state = UIGestureRecognizerStateChanged;
      } else {
            [self fail];
            self.state = UIGestureRecognizerStateFailed;
      }
    }
    
    - (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event {
      [self fail];
      [super touchesEnded:touches withEvent:event];
    }
    
    - (void)touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event {
      [self fail];
      [super touchesCancelled:touches withEvent:event];
    }
    

    您需要在.h中定义

    @property(nonatomic) CGPoint initialLocation;
    @property(nonatomic, retain) UITouch* lastTouch;
    @property(nonatomic) BOOL gestureNotBegunYet;
    

    【讨论】:

    • 我会试试这个,非常感谢!
    • 还可以检查我的编辑以获取替代方法,如果您愿意,可以更做作但没有子类化。
    • @interface CustomLongPress() 正确吗?你离开了基类......你得到touches began跟踪吗?
    • 是的,来自 touchesBegan 的日志正在显示,@interface CustomLongPress 是正确的
    • 好的,那么,当您进入 touchesBegan 时,vc.methodHasBeenCalled 是什么?您会将其值添加到 NSLog 跟踪吗?
    【解决方案2】:

    如果我没记错的话,一旦系统检测到特定类型的手势(点击、滑动、平移、长按等),它就不能再为该触摸动作发送不同类型的手势。

    这并不妨碍您实现您想要的结果。也许结合重载以下UIResponder 方法:

    – touchesBegan:withEvent:
    – touchesMoved:withEvent:
    – touchesEnded:withEvent:
    – touchesCancelled:withEvent:
    

    并且使用手势识别器(不确定输入是否会被一个人使用而另一个人会忽略),您可以确定它是“长滑动”

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-05
      • 1970-01-01
      • 2014-09-22
      • 2011-07-13
      相关资源
      最近更新 更多