1

I am trying to implement zoom in my app. But I have encountered difficulties.

What I have done so far:

(NOTE: this app is a game, so it does not use invalidate but a thread)

Rendering and the scaling:

public void render(Canvas c) {
    super.draw(c);

    if (c != null) {
        int ss = c.getSaveCount();
        c.scale(scaleFactor, scaleFactor);
        //Rendering stuff
        c.restoreToCount(ss);
    }
}

Current zoom:

(this is called from onTouchEvent in the master class when there are two pointers. THese classes are nested. )

class scaler extends ScaleGestureDetector {
    public scaler(Context context, OnScaleGestureListener listener) {
        super(context, listener);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        listener.onScale(this);
        return super.onTouchEvent(event);
    }

    @Override
    public float getScaleFactor() {
        return super.getScaleFactor();
    }
}
float startScale;
float endScale;
class ScaleListener implements ScaleGestureDetector.OnScaleGestureListener{


        @Override
        public boolean onScale(ScaleGestureDetector detector) {
            startScale = detector.getScaleFactor();
            scaleFactor *= detector.getScaleFactor();
            scaleFactor = (scaleFactor < 1 ? 1 : scaleFactor); // prevent our view from becoming too small //
            scaleFactor = ((float)((int)(scaleFactor * 100))) / 100; // Change precision to help with jitter when user just rests their fingers //
            return true;
        }

        @Override
        public boolean onScaleBegin(ScaleGestureDetector detector) {
            return true;
        }

        @Override
        public void onScaleEnd(ScaleGestureDetector detector) {

        }


}

I have been looking on several questions on SO, and all I have found does not work properly. There are various reasons for the solutions.

The one I am currently using:

Zooms in before zooming out(the scalefactor drops down before zooming out)
It does not zoom in on the area the fingers are in.

So how can I add zoom that zooms in on the area the fingers are in, and make a it so it zooms without resetting the zoom so it is really zoomed in?

Zoe
  • 27,060
  • 21
  • 118
  • 148
  • do not override `ScaleGestureDetector#onTouchEvent`: you have to call this method from your `MotionEvent` dispatching method – pskink Mar 08 '17 at 16:04
  • I don't follow. Are you saying that I should call ScaleListener(the class I have) `.onScale()` from OnTouchEvent in the SurfaceView?(I call ScaleGestureDetector.onTouchEvent from SurfaceView.onTouchEvent) – Zoe Mar 08 '17 at 16:06
  • read https://developer.android.com/reference/android/view/ScaleGestureDetector.html (the second bullet) – pskink Mar 08 '17 at 16:07
  • Which part? Read through it, several times too. I cannot find anything there that helps me The link is documentation, not anything on integration – Zoe Mar 08 '17 at 16:09
  • (the second bullet) – pskink Mar 08 '17 at 16:10
  • and no, you shouldnt extend `ScaleGestureDetector` at all – pskink Mar 08 '17 at 16:12
  • This is my first go at zooming. I don't really know what I'm doing, and why I should/should not do some things. – Zoe Mar 08 '17 at 16:14
  • so in the link i posted you can find: `"To use this class: ..."` – pskink Mar 08 '17 at 16:15
  • Create an instance for the view(the `scaler`-class) and call onTouchEvent in ScaleGestureDetector from onTouchEvent in the view – Zoe Mar 08 '17 at 16:17
  • yes, exactly, and your listener methods will be called – pskink Mar 08 '17 at 16:19
  • Automatically?? – Zoe Mar 08 '17 at 16:20
  • yes, isn't it magical? – pskink Mar 08 '17 at 16:20
  • I was not aware of that.Testing it results in it being smooth and not zooming in completely, but it still doesn't zoom around the fingers – Zoe Mar 08 '17 at 16:22
  • just add some `Log.d` inside every listener method (`onScale*`) to see when they are called – pskink Mar 08 '17 at 16:23
  • see http://stackoverflow.com/a/21657145/2252830, you can remove MoveGestureDetector and RotateGestureDetector and use only ScaleGestureDetector – pskink Mar 08 '17 at 16:30
  • I am using SurfaceView and OnTouchEvent so I haven't had a need to use MoveGestureDetector or RotateGestureDetector. Using offset I have movement, and I have no need for rotation. – Zoe Mar 08 '17 at 16:35
  • so thats why i said you can remove them and just test ScaleGestureDetector – pskink Mar 08 '17 at 16:39
  • I have tested it and now only one issue remains: Zooming in around the fingers – Zoe Mar 08 '17 at 16:42
  • `"Zooming in around the fingers"` which means? – pskink Mar 08 '17 at 18:04
  • For an instance in a browser on your phone: If you want to see a picture, but the site isn't designed for mobile, so you have to zoom to see it. Then you would expect it to zoom in on the picture, and not have the X and Y coordinates to have the same position(e.g. 0,0). Does that make sense? – Zoe Mar 11 '17 at 11:55
  • not really, you mean that scaling pivot point (the pixel that does not change during the scaling) should be between your fingers? – pskink Mar 11 '17 at 11:58
  • Yes. I tried using setPivot[X/Y] but it didn't change the zoom area – Zoe Mar 11 '17 at 12:09
  • did you try my code? doesn't it work that way? – pskink Mar 11 '17 at 12:10
  • From the link you sent earlier?[(this)](http://stackoverflow.com/questions/21633545/android-imageview-scaling-and-translating-issue/21657145#21657145)? I haven't had a chance to try it yet, so I am going to try to use that now – Zoe Mar 11 '17 at 12:13
  • 1
    yes, just remove MoveGestureDetector and RotateGestureDetector and use only ScaleGestureDetector – pskink Mar 11 '17 at 12:15
  • I used a matrix(inspired by your code) and gave .setScale the scale and focus[X/Y] and it now zooms as expected – Zoe Mar 11 '17 at 14:18
  • i dont understand what you mean, but anyway, its good it works... ;-) – pskink Mar 11 '17 at 14:20
  • I posted an answer to(make it clear that this issue has been resolved) and to explain what solved the issues. And thanks again for the help. – Zoe Mar 11 '17 at 14:26

1 Answers1

1

Thanks to @pskink, here is what I did to solve the problem:

  1. Don't override onTouchEvent in the class extending ScaleGestureDetector, and don't call OnScaleGestureListener.onScale as it is done automatically by the detector.

This solved the issues I had with zooming.

As for zooming in on a specific area, I had to move away from using .setScale, and use a matrix instead:

public void render(Canvas c) {
    super.draw(c);

    if (c != null) {

        c.setMatrix(scaleMatrix);//scale

        //Null the matrix = set to default. 
        c.setMatrix(null);//Past this line, anything rendered is not scaled. 

    }
}

(GestureDetector should not override onTouchEvent and make a call to the listener)

And in the listener:

    public boolean onScale(ScaleGestureDetector detector) {
        startScale = detector.getScaleFactor();
        scaleFactor *= detector.getScaleFactor();

        if(scaleFactor > 2) scaleFactor = 2;//Limit max
        else if(scaleFactor < 0.3f) scaleFactor = 0.3f;//limit min
        scaleFactor = ((float)((int)(scaleFactor * 100))) / 100;//jitter-protection
        scaleMatrix.setScale(scaleFactor, scaleFactor, detector.getFocusX(), detector.getFocusY());//setScale, as I don't need to scale several things. 

        return true;
    }
Zoe
  • 27,060
  • 21
  • 118
  • 148