I'm obviously missing something big and simple, but I can't find it. I've got surface view with a background image, several moving/movable sprites, and can zoom and pan the image. Everything works fine... except when touching with a second pointer if the canvas is translated.
If the canvas is at 0, 0, no problem. If the canvas is translated, no problem with first pointer. But, if second finger touches, it snaps to 0,0. Lift second finger, and it snaps back to translated.
Seemed like a simple fix - if second pointer, keep translated value. But this is the problem - logging shows that it does keep tx value - it never shows 0,0 anywhere.
I've tried using the if (activePointer != INVALID_POINTER_ID)
method & it does same thing. I just can't figure out what is telling the canvas to jump to 0,0 when log shows the translate value has not changed.
Here is a sample of one of my many head-banging tries:
boolean doTouchEvent(MotionEvent ev) {
synchronized (gvSurfaceHolder) {
mScaleDetector.onTouchEvent(ev);
float x = ev.getX(0);
float y = ev.getY(0);
// get pointer index from the event object
int pointerIndex = ev.getActionIndex();
// get pointer ID
int pointerId = ev.getPointerId(pointerIndex);
switch (ev.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
contact = false;
// mLastTouch handles the finger position for moving the sprites
// translate handles where to move the whole screen when NOT touching sprites
mLastTouchX = x / mScaleFactor;
mLastTouchY = y / mScaleFactor;
//We assign the current X and Y coordinate of the finger to startX and startY minus the previously
//translated amount for each coordinates This works even when we are translating the first
//time because the initial values for these two variables is zero.
startX = x - previousTranslateX;
startY = y - previousTranslateY;
detectPCTouch();
if (contact){
mLastTouchX = startX / mScaleFactor;
mLastTouchY = startY / mScaleFactor;
}testVarDump("Down", pointerIndex, pointerId);
break;
case MotionEvent.ACTION_POINTER_DOWN:
stopTranslate = true;
testVarDump("ACTION Pointer DOWN", pointerIndex, pointerId);
break;
case MotionEvent.ACTION_MOVE:
x = ev.getX(0);
y = ev.getY(0);
//testVarDump("ACTION Move", pointerIndex, pointerId);
// Only move if the ScaleGestureDetector isn't processing a gesture.
if (!mScaleDetector.isInProgress()){
if (!contact){
translateX = x - startX;
translateY = y - startY;
mLastTouchX = x / mScaleFactor;
mLastTouchY = y / mScaleFactor;
}else{
translateX = previousTranslateX;
translateY = previousTranslateY;
mLastTouchX = (x - previousTranslateX) / mScaleFactor;
mLastTouchY = (y - previousTranslateY) / mScaleFactor;
}
}
break;
case MotionEvent.ACTION_POINTER_UP:
contact = false;
stopTranslate = true;
testVarDump("ACTION Pointer UP", pointerIndex, pointerId);
break;
case MotionEvent.ACTION_UP:
// All fingers went up, so let's save the value of translateX and translateY into
// previousTranslateX and previousTranslate
if (!contact){
previousTranslateX = translateX;
previousTranslateY = translateY;
}else{
translateY = previousTranslateY;
translateX = previousTranslateX;
}
contact = false;
stopTranslate = false;testVarDump("ACTION Up", pointerIndex, pointerId);
break;
}
}
return true;
}
The run block:
@Override
public void run() {
while (running) {
Canvas c = null;
try {
c = gvSurfaceHolder.lockCanvas(null);
synchronized (gvSurfaceHolder) {
c.save();
c.scale(mScaleFactor, mScaleFactor);
//If translateX times -1 is lesser than zero, let's set it to zero. This takes care of the left bound
if((translateX * -1) < 0)
translateX = 0;
//This is where we take care of the right bound. We compare translateX times -1 to (scaleFactor - 1) * displayWidth.
//If translateX is greater than that value, then we know that we've gone over the bound. So we set the value of
//translateX to (1 - scaleFactor) times the display width. Notice that the terms are interchanged; it's the same
//as doing -1 * (scaleFactor - 1) * displayWidth
else if((translateX * -1) > (mScaleFactor - 1) * screenW)
translateX = (1 - mScaleFactor) * screenW;
if(translateY * -1 < 0)
translateY = 0;
//We do the exact same thing for the bottom bound, except in this case we use the height of the display
else if((translateY * -1) > (mScaleFactor - 1) * screenH)
translateY = (1 - mScaleFactor) * screenH;
if (!mScaleDetector.isInProgress())
c.translate(translateX / mScaleFactor, translateY / mScaleFactor);
// Here I'd expect translateX to be 0, but always logs as correctly
// translated, even when the background snaps to 0,0 with second pointer touch
if (stopTranslate)
testVarDump("DRAW", 0 ,0);
updateBadGuys();
detectCollision();
draw(c);
c.restore();
}
} finally {
if (c != null)
gvSurfaceHolder.unlockCanvasAndPost(c);
}
}
I'm going a little nuts here - any idea what is forcing the translation JUST when a second finger is up or down? Please help - what the heck am I missing?