閉じる

ScaleGestureDetectorと GestureDetectorを組み合わせる

Android 2.2より実装された ScaleGestureDetector。
onTouchイベントをこいつへ食わせるだけでマルチタッチでのドラッグとピンチイン/アウトは簡単に実装できる。
が、従来からある GestureDetectorの機能、タッチ系やシングルタッチでのドラッグは ScaleGestureDetectorには含まれていない。
どうにか組み合わせて使えないかと調べてみたけれど、独自実装しか見あたらないので試行錯誤してみた。
今のところ以下のようなコードでほぼ期待通り*1 に動いている。

@Override
public boolean onTouch(View v, MotionEvent event) {
if (mScaleGestureDetector != null) {
final boolean isInProgres = mScaleGestureDetector.isInProgress();
mScaleGestureDetector.onTouchEvent(event);
if (isInProgres || mScaleGestureDetector.isInProgress()) {
return true;
}
}
if (mGestureDetector != null) {
return mGestureDetector.onTouchEvent(event);
}
return false;
}

要はScaleGestureDetectorがイベントを食べ始めたタイミング、食べている最中、食べ終わったタイミングではそのまま帰り、それ以外は GestureDetector行きと。
ScaleGestureDetector.onTouchが戻り値をしっかり処理してくれれば isInProgress()周りの処理が簡潔になるんだが。
2011/12/15追記
実機を入手したので調べてみた。
GestureDetector.onScrollにおいて単純に distanceX/distanceYだけをみてスクロールを実現していたのだけど、「一点目のタッチでスクロール開始&一時停止、二点目をタッチ、一点目を離す」という手順を踏んだ場合、distanceX/distanceYだけを見ていると一点目を離した時点で一点目の位置から二点目の位置へ飛んだように見える。
これは多くの場合は期待しない動作になる…と思われる。
これを回避するには onScrollに渡される MotionEventもチェックする必要がある。
具体的には以下のように同一のポインタID間の Distanceかをチェックすると。

@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2,float distanceX, float distanceY) {
if (e1.getPointerId(0) == e2.getPointerId(0)) {
// スクロール処理
return true;
}
return false;
}

同じ事は GestureDetector.onFlingにも当てはまるので必要であればチェックするコードをいれたほうが良いかも。

2013/04/03追記

結局の所、凝った処理をするならこれらのサポートライブラリを使わずに自分で書くのが一番楽な気がする。

2013/09/01追記

画像のビューワでよくある、「フリップで複数の ImageViewを切り替えつつ、ピンチイン/アウトで拡大縮小可能、拡大時はシングルドラッグでスクロール可能、拡大された ImageViewを端までスクロールさせるとシームレスにフリップへ移行、長押しすればコンテキストメニューも表示」という案件ではカスタム ViewPagerに ScaleGestureDetectorと GestureDetectorを組み合わせたようなクラスを作成して対応した。
それなりに悩みはしたけど、結果として無理に既存の ScaleGestureDetector/GestureDetectorを使うよりは楽だったと思う。

2013/09/05追記

Android 4.xのソースにそのものずばりに近い物を見つけた : photoviewersampleを 2.xで動かしてみる

結局、泥臭くやるしかなさそうだ。


*1 マルチタッチ-シングルタッチ間の移行するタイミングで異常なドラッグ動作になる事があるのだけど、GestureDetectorがマルチタッチを処理できていないだけだと思う。二つ目以降のタッチに関するイベントを捨ててやればいける気がするけどマルチタッチ対応の実機は所有していないので今のところ放置。

ScaleGestureDetectorと GestureDetectorを組み合わせる」への1件のフィードバック

コメントを残す

メールアドレスが公開されることはありません。必須項目には印がついています *

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)