web-dev-qa-db-ja.com

UIGestureRecognizerはUIWebViewで動作しますか?

UIScrollViewのサブビューであるUIWebviewで動作するUIGestureRecognizerを取得しようとしています。これは奇妙に聞こえますが、numberOfTouchesRequiredを2に設定するとセレクタが起動しますが、numberOfTouchesRequiredを1に設定するとセレクタは起動しません。

ここに私のコードがあります:

UITapGestureRecognizer *tap1 = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(select1:)];
    tap1.numberOfTouchesRequired = 2;
    tap1.numberOfTapsRequired = 1;
    tap1.delegate = self;
    [self.ans1WebView addGestureRecognizer:tap1];
    [tap1 release];

- (void) select1:(UILongPressGestureRecognizer *)sender {
    //Do Stuff
}

UIGestureRecognizerのAppleサンプルを使用し、ペン先にWebビューを挿入することでこれを確認しました。タップコードは、Webビューの領域内を除くすべての場所で機能します。

40
rscott

私が見たものから、UIWebViewは他の人とうまく機能しません。ジェスチャ認識エンジンの場合、次からYESを返してみてください。

_- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer;
_

3.0との後方互換性が必要だったため、UIWebView内でJavascriptを使用してすべてのジェスチャー処理を行うことになりました。良い解決策ではありませんが、私のニーズにはうまくいきました。要素を長押ししたり、タップ、スワイプ、ピンチ、回転したりすることができました。もちろん、ローカルコンテンツのみを使用していました。

編集:

UIWebViewのデリゲートにメッセージを送信する例については、 PhoneGap をご覧ください。簡単に言うと、_document.location = "myscheme:mycommand?myarguments"_を使用してから、このデリゲートコールバックからコマンドと引数を解析します。

_-(BOOL) webView:(UIWebView *)inWeb shouldStartLoadWithRequest:(NSURLRequest *)inRequest navigationType:(UIWebViewNavigationType)inType {
  if ( [[[inRequest URL] absoluteString] hasPrefix:@"myscheme:"] ) {
    //.. parse arguments
    return NO;
  }
}
_

PhoneGapコードで、メッセージを送信するためのキューとタイマーが設定されていることがわかります。使用状況によっては、同じことを行う必要がある場合があります。このトピックのSOには他にも質問があります。

こちらが イベント処理 のドキュメントです。私の場合、<body onload="myloader();">からdocumentにイベントリスナーを追加しました

_function myloader() {
    document.addEventListener( 'touchcancel' , touch_cancel , false );
    document.addEventListener( 'touchstart' , touch_start , false );
    document.addEventListener( 'touchmove' , touch_move , false );
    document.addEventListener( 'touchend' , touch_end , false );
};
_

実際のイベント処理は、ニーズに大きく依存します。各イベントハンドラは、各アイテムが Touch であるtouchesプロパティを持つ TouchEvent を受け取ります。タッチスタートハンドラーで開始時刻と場所を記録できます。タッチが遠くに移動するか、間違った時間が経過しても、長いタッチではありません。

WebKitは、長いタッチを処理して選択とコピーを開始しようとする場合があります。イベントハンドラでは、event.preventDefault();を使用してデフォルトの動作を停止できます。また、いくつかの点で_-webkit-user-select:none_ cssプロパティが便利であることがわかりました。

_var touch = {};
function touch_start( event /*TouchEvent*/ {
  event.preventDefault();
  touch = {};
  touch.startX = event.touches.item(0).pageX;
  touch.startY = event.touches.item(0).pageY;
  touch.startT = ( new Date() ).getTime();
}
_

これは、私がjavascriptを使用した2番目のプロジェクトです。他の場所でより良い例を見つけることができます。

ご覧のとおり、これは問題に対する迅速な答えではありません。私は得た結果にかなり満足しています。私が作業していたhtmlには、1つまたは2つのリンク以外のインタラクティブな要素はありませんでした。

67
drawnonward

UIWebViewには独自のプライベートビューがあり、ジェスチャレコグナイザも添付されています。したがって、優先ルールにより、UIWebViewに追加されたジェスチャレコグナイザが適切に機能しなくなります。

1つのオプションは、UIGestureRecognizerDelegateプロトコルを実装し、ジェスチャーRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizerメソッドを実装することです。他のタップジェスチャの場合、このメソッドからYESを返します。この方法では、タップハンドラーが呼び出されますが、Webビューは引き続き呼び出されます。

Apple dev forums でこれを参照してください。

45
Don Wilson

これはいくぶんハック的なソリューションですが、動作します。 UIWebViewには、プライベートAPIを使用しないと通常アクセスできない多くの内部ジェスチャー認識機能があります。ただし、gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:を実装すると、すべて無料で入手できます。その時点で、すべての内部UITapGestureRecognizerに、独自のUITapGestureRecognizerが失敗した場合にのみ起動するように指示できます。それを一度だけ実行してから、独自のジェスチャー認識エンジンからデリゲートを削除します。その結果、webViewをパンおよびスクロールすることはできますが、(単一の)タップジェスチャを受信しなくなります。

- (void)viewDidLoad 
{      
    [super viewDidLoad];

    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapGesture:)];

    // view is your UIViewController's view that contains your UIWebView as a subview
    [self.view addGestureRecognizer:tap];

    tap.delegate = self;
}

- (void)handleTapGesture:(UITapGestureRecognizer *)gestureRecognizer
{
    NSLog(@"tap!");

    // this is called after gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer: so we can safely remove the delegate here
    if (gestureRecognizer.delegate) {
        NSLog(@"Removing delegate...");
        gestureRecognizer.delegate = nil;
    }
}

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
    if ([otherGestureRecognizer isKindOfClass:[UITapGestureRecognizer class]]) {
        [otherGestureRecognizer requireGestureRecognizerToFail:gestureRecognizer];

        NSLog(@"added failure requirement to: %@", otherGestureRecognizer);
    }

    return YES;
}

楽しい!

13

私は同じ問題を抱えていました。このソリューションは私のために働いた:

1)インターフェースにプロトコルを追加してください:UIGestureRecognizerDelegate例:

@interface ViewController : UIViewController <SlideViewProtocol, UIGestureRecognizerDelegate>

2)このコード行を追加します

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

3)ジェスチャーのセットアップ

UISwipeGestureRecognizer *swipeGesture = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(nextSlide)];
swipeGesture.numberOfTouchesRequired = 1;
swipeGesture.direction = (UISwipeGestureRecognizerDirectionLeft);
swipeGesture.cancelsTouchesInView = YES; [swipeGesture setDelegate:self];
[self.view addGestureRecognizer:swipeGesture];
4
chrisallick
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer*)otherGestureRecognizer {
    return YES;
}
3
Bhoopi

別の方法は、透明なUIButtonをUIWebViewの上に配置し、このボタンからのタップを処理することです。場合によっては、それは良い解決策かもしれません。

UIWebView webView = [UIWebView new];
//...

UIButton *transparentButton = [UIButton buttonWithType:UIButtonTypeCustom];
[transparentButton addTarget:self action:@selector(buttonTapped) forControlEvents:(UIControlEventTouchUpInside)];
transparentButton.frame = webView.frame;
transparentButton.layer.backgroundColor = [[UIColor clearColor] CGColor];
[self.view transparentButton];
2
Sergey

また、私の答え here が役立つかもしれません。 UIWebViewのjavascriptでピンチジェスチャを処理する実用的な例です。

(必要に応じて、Objective-Cにイベントを返すことができます。 私の答えはこちら を参照してください。)

1
zekel