如何在放大时find点击的绝对位置

请参阅下面的每个部分,以三种不同的方式描述我的问题。 希望能帮助人们回答。

问题:如果给定原始缩放点和缩放因子,只有用放大的图像表示坐标时,如何find以canvas /用户空间表示的一对坐标?

实践中的问题:

我目前正在尝试复制应用程序中使用的缩放function,例如图库/地图,当您可以捏缩放缩放时,缩放将朝缩放的中点移动。

向下保存缩放的中心点(基于当前屏幕,在X,Y坐标中)。 然后,当检测到“缩放”手势时,我有这个function:

class ImageScaleGestureDetector extends SimpleOnScaleGestureListener { @Override public boolean onScale(ScaleGestureDetector detector) { if(mScaleAllowed) mCustomImageView.scale(detector.getScaleFactor(), mCenterX, mCenterY); return true; } } 

CustomImageView的缩放function如下所示:

 public boolean scale(float scaleFactor, float focusX, float focusY) { mScaleFactor *= scaleFactor; // Don't let the object get too small or too large. mScaleFactor = Math.max(MINIMUM_SCALE_VALUE, Math.min(mScaleFactor, 5.0f)); mCenterScaleX = focusX; mCenterScaleY = focusY; invalidate(); return true; } 

缩放图像的绘制是通过覆盖onDraw方法实现的,该方法将canvas围绕中心缩放,并将图像绘制到其上。

 @Override public void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.save(); canvas.translate(mCenterScaleX, mCenterScaleY); canvas.scale(mScaleFactor, mScaleFactor); canvas.translate(-mCenterScaleX, -mCenterScaleY); mIcon.draw(canvas); canvas.restore(); } 

从ScaleFactor 1缩放时,这一切正常,这是因为最初的mCenterX和mCenterY是基于设备屏幕的坐标。 10,10在设备上是10,10在canvas上。

然而,在已经放大之后,下次单击位置10,10时,由于已经执行的缩放和变换,它将不再对应于canvas中的10,10。

抽象问题:

下面的图像是围绕中心点A的缩放操作的示例。每个框表示在该比例因子(1,2,3,4,5)时视图的位置和大小。

例

在这个例子中,如果你用A缩放2倍,那么你点击位置B,X,Y报告为B将基于屏幕位置 – 而不是相对于初始canvas0,0的位置。

我需要find一个获得B的绝对位置的方法

Solutions Collecting From Web of "如何在放大时find点击的绝对位置"

所以,在重新绘制问题后,我find了我正在寻找的解决scheme。 它经历了几次迭代,但是这是我如何解决的:

解决方案描述

B – 点,规模操作的中心

A1,A2,A3 – 点在用户空间上相等,但在canvas空间上不同。

您知道BxBy的值,因为无论比例因子如何(在canvas-space和用户空间中都知道这个值)它们总是不变的。

你在用户空间知道AxAy ,所以你可以findAxBxAyBy的距离。 这种测量是在用户空间,将其转换为canvas空间测量,只需将其除以缩放因子即可。 (一旦转换为canvas空间,您可以看到这些线条以红色,橙色和黄色)。

由于B点是恒定的,它与边缘之间的距离是恒定的(用蓝线表示)。 这个值在用户空间和canvas空间是相等的。

您知道canvas空间中Canvas的宽度,因此通过从canvas空间中的点A的坐标剩余的总宽度中减去这两个canvas空间度量( AxBxBxEdge ):

 public float[] getAbsolutePosition(float Ax, float Ay) { float fromAxToBxInCanvasSpace = (mCenterScaleX - Ax) / mScaleFactor; float fromBxToCanvasEdge = mCanvasWidth - Bx; float x = mCanvasWidth - fromAxToBxInCanvasSpace - fromBxToCanvasEdge; float fromAyToByInCanvasSpace = (mCenterScaleY - Ay) / mScaleFactor; float fromByToCanvasEdge = mCanvasHeight - By; float y = mCanvasHeight - fromAyToByInCanvasSpace - fromByToCanvasEdge; return new float[] { x, y }; } 

上面的代码和图像描述了当您点击原始中心的左上方时。 我使用相同的逻辑来findA,而不pipe它位于哪个象限,并重构为以下内容:

 public float[] getAbsolutePosition(float Ax, float Ay) { float x = getAbsolutePosition(mBx, Ax); float y = getAbsolutePosition(mBy, Ay); return new float[] { x, y }; } private float getAbsolutePosition(float oldCenter, float newCenter, float mScaleFactor) { if(newCenter > oldCenter) { return oldCenter + ((newCenter - oldCenter) / mScaleFactor); } else { return oldCenter - ((oldCenter - newCenter) / mScaleFactor); } } 

这是基于Graeme的答案我的解决scheme:

 public float[] getAbsolutePosition(float Ax, float Ay) { MatrixContext.drawMatrix.getValues(mMatrixValues); float x = mWidth - ((mMatrixValues[Matrix.MTRANS_X] - Ax) / mMatrixValues[Matrix.MSCALE_X]) - (mWidth - getTranslationX()); float y = mHeight - ((mMatrixValues[Matrix.MTRANS_Y] - Ay) / mMatrixValues[Matrix.MSCALE_X]) - (mHeight - getTranslationY()); return new float[] { x, y }; } 

参数Ax和Ay是用户通过onTouch()触摸的点,我在MatrixContext类中拥有我的静态matrix实例来保存以前的缩放/转换值。

真的很抱歉,这是一个简短的回答,急于求成。 但我最近也在看这个 – 我发现http://code.google.com/p/android-multitouch-controller/做你想做的(我想 – 我不得不阅读你的文章)。 希望这可以帮助。 今晚我会有一个适当的看看,如果这没有帮助,看看我能否进一步帮助。