ios - 结合向下滑动和长按

标签 ios uigesturerecognizer

我试图在我的 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 的日志

最佳答案

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

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

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

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

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

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

您可以这样配置它们:

C --> B --> A

特此x --> y表示x需要 y失败。因此,您将拥有 C (您的长按手势识别器)将需要 B GR 失败和 B需要 A (您的滑动识别器)失败; B一旦 A 就会失败将识别滑动;一次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;

关于ios - 结合向下滑动和长按,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13726705/

相关文章:

iphone - UIButton 触摸事件落入底层 View

ios - HTTP.Body 参数问题 - Swift

iOS-如何在限制范围内绘画

php - iOS 存折后栏中的特殊字符

objective-c - 与 UIButton 对象一起识别滑动方向

swift - 一个 View 上有两个 UIGestureRecognizer?

iphone - 将地址地理编码为 iPhone 中的坐标

Swift 如何初始化函数以提高性能

ios - 让 UIView 响应快速、快速的单击的最佳方法是什么?

ios - GestureRecognizer 的 Action 不会触发