2

私は ViewController (tableView を持つ) に、次々に動作する必要がある 2 つのジェスチャ認識機能を実装しようとしています。1 つ目は下にスワイプするジェスチャで、2 つ目は長押しジェスチャです。

@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 に関してはログを取得しません

4

2 に答える 2

1

そのためには、独自のカスタム ジェスチャ認識エンジンを作成する必要があります。最良の方法は、サブクラス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>は、スワイプ アクションにグローバル フラグを設定することです (スワイプ アクションの実行時に設定すると、カスタム認識エンジンがその値を読み取ります)。これは簡単ですが、見つけることができる最良の実装ではありません。

もう 1 つのアプローチは、3 つの標準ジェスチャ レコグナイザをチェーンすることに依存することrequiresGestureRecognizerToFailです。これらを A、B、および C と呼びましょう。

  1. A はUISwipeGestureRecognizer;
  2. C はUILongPressGestureRecognizer;
  3. B は任意のジェスチャ レコグナイザーです。

次のように設定します。

C --> B --> A

それによって、失敗する必要があることx --> yを示します。したがって、(長押しジェスチャ認識エンジン) はGR が失敗する必要があり、 (スワイプ認識エンジン) が失敗する必要があります。スワイプが認識されるとすぐに失敗します。一度失敗すると、長押しがあれば認識させられます。xyCBBABABC

編集:

あなたのコメントを読んだ後、これを試してみて、それが役立つかどうかを確認していただけませんか:

  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;
于 2012-12-05T15:41:43.177 に答える
0

私が間違っていなければ、システムが特定の種類のジェスチャ (タップ、スワイプ、パン、長押しなど) を検出すると、そのタッチ アクションに対してさまざまな種類のジェスチャを送信できなくなります。

これにより、目的の結果が得られなくなることはありません。UIResponderおそらく、次のメソッドのオーバーロードを組み合わせて使用​​します。

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

また、ジェスチャ認識機能を使用すると (入力が一方によって消費され、他方によって無視されるかどうかは不明です)、それが「長いスワイプ」であると判断できます。

于 2012-12-05T15:40:09.713 に答える