[iPhone] UIWebView のタッチイベントを取得する
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
関連する投稿
7 comments
コメントをどうぞ
Additional comments powered by BackType
[blog] [iPhone] UIWebView のタッチイベントを取得する http://is.gd/cgU67
This comment was originally posted on Twitter
Sun Limited Mt. – [iPhone] UIWebView のタッチイベントを取得する http://www.syuhari.jp/blog/archives/2141
This comment was originally posted on Twitter
このコード大変助かりました、ありがとうございます。
しかし、GestureWindowのdelegateインスタンス変数ですが、UIWindow(または親クラス)のdelegate を重なるのか GestureWindow を使うと Auto Rotate が上手く動作しなくなります。 delegateインスタンス変数名を wDelegate に変更したところ正しく動作するようになりました。
確かにdelegateを使ってはダメですね。ご指摘ありがとうございました
[...] http://blog.syuhari.jp/archives/2141 UIWindowでイベント拾ってそれをViewへ投げる。 [...]
[...] そこでぐぐったところこのサイトがヒットした。 ここを参考にしつつクラス『UIGestureWindow』を作った。 [...]
2techrepublic…
…