[Android]ビュアーもどきズーム機能を...

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
ひよつこ

[Android]ビュアーもどきズーム機能を...

#1

投稿記事 by ひよつこ » 12年前

お久しぶりです、ひよつこです。
今回もお世話になります。

現在開発中のビュアーもどきアプリに本格的にズーム機能を付けよう思っています。
そこでView.OnTouchListenerを継承した拡大率と移動したx,y座標を返すリスナーを作りました。
下のコードはそれを実装したカスタムビューのコードです。

コード:

	private CustomListener vListener;
	private float pinchStartDistance = 0.0f;
	private PointF pinchStartPoint = new PointF();
	private float totalScale = 1.0f;
	private PointF totalMove = new PointF();
	private int touchMode = TOUCH_NONE;
	private static final int TOUCH_NONE  = 0;
	private static final int TOUCH_DRAG  = 1;
	private static final int TOUCH_ZOOM  = 2;
	private static final int TOUCH_FLICK = 3;
	public final boolean TURN_RIGHT = true;
	public final boolean TURN_LEFT = false;
	public final boolean TOUCHED_NOW = true;
	public final boolean TOUCHED_FINISH = false;

	private View.OnTouchListener tListener = new View.OnTouchListener(){
		@Override
		public boolean onTouch(View v, MotionEvent event) {
			//ピンチ操作でズーム処理をする
			switch(event.getAction() & MotionEvent.ACTION_MASK){
			//ピンチ操作開始
			case MotionEvent.ACTION_POINTER_DOWN:
				if(event.getPointerCount() >= 2){
					pinchStartDistance = getDistance(event);
					if(pinchStartDistance > 50f){
						pinchStartPoint = getCenterPoint(event);
						totalMove.x += pinchStartPoint.x * totalScale;
						totalMove.y += pinchStartPoint.y * totalScale;
						touchMode = TOUCH_ZOOM;
					}
				}
				break;
			//ピンチ操作中
			case MotionEvent.ACTION_MOVE:
				if(touchMode == TOUCH_ZOOM && pinchStartDistance > 0){
					float scale = 1.0f;
					scale = getDistance(event) / pinchStartDistance;
					scale *= totalScale;
					vListener.onPageZoom(totalMove.x,totalMove.y,scale,false);
				}
				break;
			//ピンチ操作終了
			case MotionEvent.ACTION_UP:
			case MotionEvent.ACTION_POINTER_UP:
				if(touchMode == TOUCH_ZOOM){
					totalScale = getDistance(event) / pinchStartDistance * totalScale;
					pinchStartPoint.x = 0.0f;
					pinchStartPoint.y = 0.0f;
					if(totalScale < 1.0f){
						totalScale = 1.0f;
						totalMove.x = totalMove.y = 0.0f;
						touchMode = TOUCH_NONE;
					}
					vListener.onPageZoom(totalMove.x, totalMove.y, totalScale, true);
				}
			}
			//ズーム中にドラッグ操作をするとビュアーをスライドする...のが目的
			switch(event.getAction() & MotionEvent.ACTION_MASK){
			//ドラッグ操作開始
			case MotionEvent.ACTION_DOWN:
				if(touchMode == TOUCH_ZOOM & event.getPointerCount() == 1){
					pinchStartPoint.x = event.getX();
					pinchStartPoint.y = event.getY();
					touchMode = TOUCH_DRAG;
				}
				break;
			//ドラッグ操作中
			case MotionEvent.ACTION_MOVE:
				if(touchMode == TOUCH_DRAG){
					float moveX = totalMove.x - (event.getX() - pinchStartPoint.x);
					float moveY = totalMove.y - (event.getY() - pinchStartPoint.y);
					vListener.onPageDrag(moveX, moveY, false);
				}
				break;
			//ドラッグ操作終了
			case MotionEvent.ACTION_UP:
				if(touchMode == TOUCH_DRAG){
					totalMove.x = totalMove.x - (event.getX() - pinchStartPoint.x);
					totalMove.y = totalMove.y - (event.getY() - pinchStartPoint.y);
					touchMode = TOUCH_ZOOM;
					if(totalMove.x < 0.0f){
						totalMove.x = 0.0f;
					}else if(totalMove.x > viewerWidth){
						totalMove.x = viewerWidth;
					}
					if(totalMove.y < 0.0f){
						totalMove.y = 0.0f;
					}else if(totalMove.y > viewerHeight){
						totalMove.y = viewerHeight;
					}
					vListener.onPageDrag(totalMove.x, totalMove.y, true);
				}
			}
			//フリック操作でビュアーのページを更新
			switch(event.getAction() & MotionEvent.ACTION_MASK){
			//フリック操作開始
			case MotionEvent.ACTION_DOWN:
				if(touchMode == TOUCH_NONE & event.getPointerCount() == 1){
					pinchStartPoint.x = event.getX();
					touchMode = TOUCH_FLICK;
				}
				break;
			//フリック操作終了
			case MotionEvent.ACTION_UP:
				if(touchMode == TOUCH_FLICK){
					if(event.getX() - pinchStartPoint.x < - viewerWidth / 2){
						vListener.onTurnPage(TURN_RIGHT);	//左向きにページめくり
					}else if(event.getX() - pinchStartPoint.x > viewerWidth / 2){
						vListener.onTurnPage(TURN_LEFT);	//右向きにページめくり
					}
					touchMode = TOUCH_NONE;
				}
				break;
			}
			return true;
		}
	};

	//ピンチ距離取得用
	private	float getDistance(MotionEvent event) {
		if(event.getPointerCount() > 1){
			float x = event.getX(0) - event.getX(1);
			float y = event.getY(0) - event.getY(1);
			return android.util.FloatMath.sqrt(x * x + y * y);
		}else{
			return pinchStartDistance;
		}
	}

	//ピンチ開始座標取得用
	private	PointF getCenterPoint(MotionEvent event) {
		PointF pt = pinchStartPoint;
		if(event.getPointerCount() > 1){
			pt.x = (event.getX(0) + event.getX(1)) * 0.5f;
			pt.y = (event.getY(0) + event.getY(1)) * 0.5f;
		}
		return pt;
	}
といった感じのコードになりました。

しかしこのリスナーを実装してからの処理がわかりません。
受け取った引数を元にMatrixを作成し、カスタムビューに設定したいのですが、
具体的にどのようにMatrixを使えばいいのでしょうか。
リスナーの方に問題がある場合もご指摘よろしくお願いします。

ひよつこ

Re: [Android]ビュアーもどきズーム機能を...

#2

投稿記事 by ひよつこ » 12年前

お久しぶりです。
ひよつこです。

前回は丸投げしたような質問の仕方ですみませんでした。
そこで今回再び質問させて頂きます。

今回ビュアーもどきにズーム機能とズーム中にスライドを付けたいと思っています。
そのための処理は以下の2つです。

1.ピンチ操作の中心の座標と拡大率(縮小率)からImageViewを拡大します。
拡大率(縮小率)はピンチ操作の前後での指の距離の比率から出します。

2.ズーム中に画面をスライドすると、ズームの状態を保ったままImageViewを平行移動します。
平行移動の処理にはスライドの前後での指の位置の違いから移動距離と方向を決定します。

これらの処理はImageViewにMatrixを設定することで行おうと思っています。
しかし、ズーム中にさらにズームした時などの処理がうまくいきません。
(具体的にはMatrix.postScale()を再びつかう)
また、ズーム中にスライドした時の処理もMatrix.postTranslate()を
使いますがどうもうまくいきません。

説明下手ですみませんがどうかよろしくお願いします。

ISLe
記事: 2650
登録日時: 15年前
連絡を取る:

Re: [Android]ビュアーもどきズーム機能を...

#3

投稿記事 by ISLe » 12年前

Matrixに計算を重ねると基準がズレていくので見た目どおりの挙動をさせるのは非常に困難です。

ズーム率とスライド距離を別々に管理し、変化があったときにオリジナルのMatrixから計算し直すのが一般的です。

Matrixを記憶しておく必要はありません。

ひよつこ

Re: [Android]ビュアーもどきズーム機能を...

#4

投稿記事 by ひよつこ » 12年前

返信ありがとうございます。

アドバイス頂いた通り、数値だけを記憶し処理の度にMatrixを作成するようにしたところ、
正しい処理をさせることができたように思います。

しかし、今度はズームしている状態からのズーム処理がうまくいかなくなってしまいました。
もう少し詳しく言うと、一度ズームをした後でさらにズームをする時に問題が発生します。
ズーム率はもともとのズーム率に新しいものをかけた積を使いますが、
Matrix.postTranslate(x,y)で使用するスライド距離の求め方がわかりません。

わかりにくい文章で申し訳ありませんが、よろしくお願いします。

ISLe
記事: 2650
登録日時: 15年前
連絡を取る:

Re: [Android]ビュアーもどきズーム機能を...

#5

投稿記事 by ISLe » 12年前

ズームしていない(ズーム率1.0)のときは正常動作しているのでしょうか。

デバイス画面上で同じ距離でも、画像が拡大表示されているとき、画像上の距離は短くなります。
スライド操作から求めた平行移動距離を、ズーム率で割るだけで良いのではないでしょうか。

ひよつこ

Re: [Android]ビュアーもどきズーム機能を...

#6

投稿記事 by ひよつこ » 12年前

返信ありがとうございます。
ズーム率をかけていなかったことが問題でした。

細かく説明してくださりありがとうございました。
次回もよろしくお願いします。

閉鎖

“C言語何でも質問掲示板” へ戻る