I've been stuck on this problem for eight hours, so I figured it was time to get some help.
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.)
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).
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;
}
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:
- 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.
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()
.
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.
onTouchEvent
. With this, you can easily find the mid point, and how much scaling is required. – Splore