2010年

[iPhone] UIWebView のタッチイベントを取得する このエントリーを含むはてなブックマーク

iPhone/iPod touch Add comments

iPhoneSDK開発のレシピのレシピ47「UIWebView をフィンガージェスチャーで操作する」書かせていただいたのですが、この処理でプライベートAPI を使用しているために、以下のように修正しまさせていただきました。GitHub のサンプルコードでは既に先月修正済みなのですが正式にアナウンスしていなかったので、改めて説明させていただきます。

やりたいことは、Firefox などのマウスジェスチャーのように UIWebView をフィンガージェスチャーで操作するということです。UIWebView ではシングルタッチはスクロールや拡大縮小などがあるため、2本指でのタッチで左右にスワイプしたときに戻る、進むという動作をさせることにします。(フレーム内のスクロールに2本指でのタッチを使用しますが、まあその辺はとりあえず置いておいて下さい)

詳細なコードは GitHub にありますので、詳しくはそちらをご参照ください。

ポイントはフィンガージェスチャーを認識するためにタッチ動作をフックする UIWindow のサブクラス GestureWindow を作り、AppDelegate でその GestureWindow を使用するところです。UIWindow の sendEvent: ですべてのタッチ動作をフックして UIWebView への2本指でのマルチタッチのときのみ、delegateを通じてタッチイベントを通知します。また、フックしたタッチイベントは全てスーパークラスへそのまま渡すことにより、通常のタッチイベントを邪魔しないようにします。

@protocol GestureWindowDelegate

- (void) touchesBeganWeb:(NSSet *)touches withEvent:(UIEvent *)event;
- (void) touchesMovedWeb:(NSSet *)touches withEvent:(UIEvent *)event;
- (void) touchesEndedWeb:(NSSet *)touches withEvent:(UIEvent *)event;

@end

@interface GestureWindow : UIWindow {
    UIWebView* wView;
    id delegate;
}

@property (nonatomic, retain) UIWebView* wView;
@property (nonatomic, assign) id delegate;

@end
@implementation GestureWindow

@synthesize wView, delegate;

-(void) dealloc {
    [wView release];
    [super dealloc];
}

- (void)sendEvent:(UIEvent *)event {
    [super sendEvent:event];
    if (wView == nil || delegate == nil) {
        return;
    }
    // 2本指でのマルチタッチか
    NSSet *touches = [event allTouches];
    if (touches.count != 2) {
        return;
    }

    UITouch *touch = touches.anyObject;
    // 指定のUIWebViewへのタッチか
    if ([touch.view isDescendantOfView:wView] == NO) {
        return;
    }

    switch (touch.phase) {
        case UITouchPhaseBegan:
            if ([self.delegate
                 respondsToSelector:@selector(touchesBeganWeb:withEvent:)]) {
                [self.delegate
                    performSelector:@selector(touchesBeganWeb:withEvent:)
                    withObject:touches withObject:event];
            }
            break;
        case UITouchPhaseMoved:
            if ([self.delegate
                 respondsToSelector:@selector(touchesMovedWeb:withEvent:)]) {
                [self.delegate
                    performSelector:@selector(touchesMovedWeb:withEvent:)
                    withObject:touches withObject:event];
            }
            break;
        case UITouchPhaseEnded:
            if ([self.delegate
                 respondsToSelector:@selector(touchesEndedWeb:withEvent:)]) {
                [self.delegate
                    performSelector:@selector(touchesEndedWeb:withEvent:)
                    withObject:touches withObject:event];
            }
        default:
            return;
            break;
    }
}

@end

関連する投稿

5 Responses to “[iPhone] UIWebView のタッチイベントを取得する”

  1. syuhari Says:

    [blog] [iPhone] UIWebView のタッチイベントを取得する http://is.gd/cgU67

    This comment was originally posted on Twitter

  2. twztest Says:

    Sun Limited Mt. – [iPhone] UIWebView のタッチイベントを取得する http://www.syuhari.jp/blog/archives/2141

    This comment was originally posted on Twitter

  3. Yuumi3 Says:

    このコード大変助かりました、ありがとうございます。

    しかし、GestureWindowのdelegateインスタンス変数ですが、UIWindow(または親クラス)のdelegate を重なるのか GestureWindow を使うと Auto Rotate が上手く動作しなくなります。 delegateインスタンス変数名を wDelegate に変更したところ正しく動作するようになりました。

  4. matsuura Says:

    確かにdelegateを使ってはダメですね。ご指摘ありがとうございました :-)

  5. WebReader アプリ開発 その1 | iPhoneサイト/iPhoneアプリ開発スタッフブログ Says:

    [...] http://blog.syuhari.jp/archives/2141 UIWindowでイベント拾ってそれをViewへ投げる。 [...]

Leave a Reply

Additional comments powered by BackType

WP Theme & Icons by N.Design Studio
Entries RSS Comments RSS ログイン