帆布捏缩放点内的界限 [英] Canvas Pinch-Zoom to Point Within Bounds
问题描述
我已经被困在这个问题上八个小时,所以我想是时候得到一些帮助。
I've been stuck on this problem for eight hours, so I figured it was time to get some help.
在我开始了我的问题,我只是让大家知道,我已经通过我发现帮助的答案本网站和谷歌,并没有。 (这的是,<一个href="http://stackoverflow.com/questions/6835224/android-bitmap-canvas-offset-after-scale">another,和<一href="http://stackoverflow.com/questions/6624103/scaling-image-of-imageview-while-maintaining-center-point-in-same-place">another.)
Before I begin my problem, I'll just let it be known that I've been through this site and Google, and none of the answers I've found have helped. (This is one, another, and another.)
这里的交易:我有一个扩展的类 SurfaceView
(姑且称之为 MySurface
),并覆盖很多方法在里面。通常情况下,绘制了几个广场和文本框,这是所有罚款。一旦用户开始触摸,将其转换为位图
,然后绘制每一帧,直到用户释放。
Here's the deal: I have a class that extends SurfaceView
(let's call it MySurface
) and overrides many methods in it. Normally, it draws several squares and text boxes, which is all fine. As soon as a user starts touching, it converts to a Bitmap
, then draws each frame that until the user releases.
下面的难题是:我想要实现这样的功能,用户可以将两个手指放在屏幕上,捏放大,并且还平移(但只能用两个手指)
Here's the rub: I want to implement such a functionality that the user can place two fingers on the screen, pinch to zoom, and also pan around (but ONLY with two fingers down).
我发现捏到变焦几个实现和适应他们给我的画布
对象 MySurface
通过如下:
I found a few implementations of pinch-to-zoom and adapted them to my Canvas
object in MySurface
via the following:
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.save();
canvas.scale(mScaleVector.z, mScaleVector.z); // This is the scale factor as seen below
canvas.translate(mScaleVector.x, mScaleVector.y); // These are offset values from 0,0, both working fine
// Start draw code
// ...
// End draw code
canvas.restore();
}
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
@Override
public boolean onScale(ScaleGestureDetector detector) {
float factor = detector.getScaleFactor();
if (Math.abs(factor - 1.0f) >= 0.0075f) {
mScaleVector.z *= factor;
mScaleVector.z = Math.max(MIN_ZOOM, Math.min(mScaleVector.z, MAX_ZOOM));
}
// ...
invalidate();
return true;
}
}
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction() & MotionEvent.ACTION_MASK;
int pointerIndex = (event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
if (event.getPointerCount() == 2) {
if (action == MotionEvent.ACTION_POINTER_DOWN && pointerIndex == 1) {
// The various pivot coordinate codes would belong here
}
}
detector.onTouchEvent(event); // Calls the Scale Gesture Detector
return true;
}
虽然这两个元素很好地工作 - 在来回滚动和双指缩放 - 有一个大问题。在双指缩放,使用时,放大到该点 0,0
而不是放大到手指点,
While both elements work fine--the scrolling back and forth and the pinch-to-zoom--there is one large problem. The pinch-to-zoom, when used, zooms into the point 0,0
, instead of zooming into the finger point.
我已经尝试了很多办法来解决这个问题:
I've tried a lot of ways to fix this:
- 使用
canvas.scale(mScaleVector.z,mScaleVector.z,mScaleVector.x,mScaleVector.y);
;显然,这会产生不想要的结果为mScaleVector
x和y的值是0的偏移量。 - 在管理一个支点坐标使用相同的偏移量为
翻译()
的方法,但这会产生是同一个0,0
问题,或者跳来跳去视图时感动。 - 在许多其他的事情......我已经做了很多与上述支点协调,努力的基础上为用户的触摸位置,并移动它相对于该触摸每个连续的手势。
- Using
canvas.scale(mScaleVector.z, mScaleVector.z, mScaleVector.x, mScaleVector.y);
; obviously, this produces unwanted results as themScaleVector
x and y values are 0-offsets. - Managing a "pivot" coordinate that uses the same offset as the
translate()
method, but this produces either the same0,0
issue, or jumping around when the view is touched. - Numerous other things... I've done a lot with the aforementioned pivot coordinate, trying to base its location on the user's first touch, and moving it relative to that touch each successive gesture.
此外,此帆布必须有界的,所以用户不能滚动永远。然而,当我使用 .scale(SX,SY,PX,PY)
方法,它远不止我在 .translate设定任何界限的事情( )
。
Additionally, this canvas must be bounded, so the user cannot scroll forever. However, when I use the .scale(sx, sy, px, py)
method, it pushes things beyond any bounds I set in .translate()
.
我... pretty的在这一点东西多开。我知道这个功能可以增加,因为它是(观看单个图像时)出现在Android 4.0的画廊。我试图追查来源$ C $ C处理这个,但没有成功。
I'm... pretty much open to anything at this point. I know this functionality can be added, as it is seen in the Android 4.0 gallery (when viewing a single image). I've tried to track down the source code that handles this, to no avail.
推荐答案
下面是code我用它来实现双指缩放在的ImageView
使用 ScaleGestureDetector
。很少或根本没有修改,你应该能够使用它太,因为你可以使用转换marices也画上一个画布
。
Here is the code I use to implement pinch zoom in an ImageView
using ScaleGestureDetector
. With little or no modification you should be able to use it too, since you can use transformation marices too, to draw on a Canvas
.
@Override
public boolean onScale(ScaleGestureDetector detector) {
float mScaleFactor = (float) Math.min(
Math.max(.8f, detector.getScaleFactor()), 1.2);
float origScale = saveScale;
saveScale *= mScaleFactor;
if (saveScale > maxScale) {
saveScale = maxScale;
mScaleFactor = maxScale / origScale;
} else if (saveScale < minScale) {
saveScale = minScale;
mScaleFactor = minScale / origScale;
}
right = width * saveScale - width
- (2 * redundantXSpace * saveScale);
bottom = height * saveScale - height
- (2 * redundantYSpace * saveScale);
if (origWidth * saveScale <= width
|| origHeight * saveScale <= height) {
matrix.postScale(mScaleFactor, mScaleFactor, width / 2, height / 2);
if (mScaleFactor < 1) {
matrix.getValues(m);
float x = m[Matrix.MTRANS_X];
float y = m[Matrix.MTRANS_Y];
if (mScaleFactor < 1) {
if (Math.round(origWidth * saveScale) < width) {
if (y < -bottom)
matrix.postTranslate(0, -(y + bottom));
else if (y > 0)
matrix.postTranslate(0, -y);
} else {
if (x < -right)
matrix.postTranslate(-(x + right), 0);
else if (x > 0)
matrix.postTranslate(-x, 0);
}
}
}
} else {
matrix.postScale(mScaleFactor, mScaleFactor, detector.getFocusX(), detector.getFocusY());
matrix.getValues(m);
float x = m[Matrix.MTRANS_X];
float y = m[Matrix.MTRANS_Y];
if (mScaleFactor < 1) {
if (x < -right)
matrix.postTranslate(-(x + right), 0);
else if (x > 0)
matrix.postTranslate(-x, 0);
if (y < -bottom)
matrix.postTranslate(0, -(y + bottom));
else if (y > 0)
matrix.postTranslate(0, -y);
}
}
return true;
}
在我的情况,我计算在视图的 onMeasure()
法neccesary值,你可能想在你的 SurfaceView
In my case, I computed the neccesary values in the onMeasure()
method of the View, you might want to do this somewhere else in your SurfaceView
width = MeasureSpec.getSize(widthMeasureSpec); // Change this according to your screen size
height = MeasureSpec.getSize(heightMeasureSpec); // Change this according to your screen size
// Fit to screen.
float scale;
float scaleX = (float) width / (float) bmWidth;
float scaleY = (float) height / (float) bmHeight;
scale = Math.min(scaleX, scaleY);
matrix.setScale(scale, scale);
setImageMatrix(matrix);
saveScale = 1f;
scaleMappingRatio = saveScale / scale;
// Center the image
redundantYSpace = (float) height - (scale * (float) bmHeight);
redundantXSpace = (float) width - (scale * (float) bmWidth);
redundantYSpace /= (float) 2;
redundantXSpace /= (float) 2;
matrix.postTranslate(redundantXSpace, redundantYSpace);
origWidth = width - 2 * redundantXSpace;
origHeight = height - 2 * redundantYSpace;
right = width * saveScale - width - (2 * redundantXSpace * saveScale);
bottom = height * saveScale - height - (2 * redundantYSpace * saveScale);
setImageMatrix(matrix);
这一点解释:
saveScale
是当前比例的位图
mScaleFactor
是你要与乘以你的缩放比例因子。
mScaleFactor
is the factor you have to multiply your scale ratio with.
maxScale
和 minScale
可以是恒定值。
宽度
和高度
是屏幕的尺寸。
redundantXSpace
和 redundantYSpace
在图像边框和屏幕边框之间的空白,因为图像中居中时,是小然后屏幕
redundantXSpace
and redundantYSpace
are the empty between the image borders and screen borders since the image is centered when in it is smaller then the screen
origHeight
和 origWidth
是位图的尺寸
基质
是用于绘制位图当前变换矩阵
matrix
is the current transformation matrix used to draw the bitmap
诀窍是,当我第一次规模化,集中在初始化的形象,我挑选的规模比例为1和 scaleMappingRatio
我映射的实际刻度值相对于所述图像
The trick is, that when I first scaled and centered the image on initialization, I picked that scale ratio to be 1 and with scaleMappingRatio
I mapped the actual scale values of the image relative to that.
这篇关于帆布捏缩放点内的界限的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!