0

I have a custom surfaceview for my CameraPreview in my app, and I am trying to implement Pinch zoom, by implementing these two methods:

@Override
    public boolean onTouchEvent(MotionEvent event) {
        Camera camera = getCamera();
        if (camera == null) {
            return true;
        }

        Camera.Parameters params = camera.getParameters();

        int action = event.getAction();

        if (event.getPointerCount() > 1) {
            if (action == MotionEvent.ACTION_POINTER_DOWN) {
                MCLog.v(TAG, "Single ");
                mDist = getFingerSpacing(event);
                MCLog.w(TAG, "Original distance " + mDist);
            } else if (action == MotionEvent.ACTION_MOVE && params.isZoomSupported()) {
                camera.cancelAutoFocus();
                handleZoom(event, params);
            }
        } else {
            if (action == MotionEvent.ACTION_UP) {

                mFirstTime = false;
                handleFocus(event, params);
            }
        }
        return true;
    }

    private void handleZoom(MotionEvent event, Camera.Parameters params) {


        if(mFirstTime) {
            mDist = getFingerSpacing(event);
            mFirstTime = false;
            return;
        }


        List<Integer> zoomRatios = params.getZoomRatios();
        int maxZoom = params.getMaxZoom();
        int zoom = params.getZoom();

        double spacing = getFingerSpacing(event);

        MCLog.w(TAG, String.format("Old zoom is: %s", zoom));

        //Percentage of displacement
        MCLog.w(TAG, String.format("Original distance is: %s, new displacement is %s", mDist, spacing));
        double percentage =  (mDist + spacing)/mDist;
        if(mDist > spacing)
        {
            percentage *= -1;
        }
        MCLog.w(TAG, String.format("Percentage is: %s", percentage));



        zoom = new Double(zoom  + percentage).intValue();
        MCLog.w(TAG, String.format("New zoom is: %s", zoom));


        if (zoom > maxZoom) {
            zoom = maxZoom;
        }

        if (zoom < 0) {
            zoom = 0;
        }
        mDist = spacing;

        params.setZoom(zoom);
        if (mZoomListener != null) {
            mZoomListener.onZoomChanged(zoomRatios.get(zoom));
        }
        getCamera().setParameters(params);
    }

This seems to be working, however the zoom has some slight delay that gets longer the more I zoom into the image. Like I would stop pinching and the image would still keep zooming in.

I couldnt find any implementation for pinch zoom in the camera besides this one, so maybe this is doing something wrong.

Community
  • 1
  • 1
M Rajoy
  • 4,028
  • 14
  • 54
  • 111

1 Answers1

0

Since you're seeing the logging continue after you lift your finger, that probably means you're not processing your touch event queue fast enough.

That setProperties call is not particularly fast.

So you'll need to rate-limit somehow, and drop touch events that you don't have time to handle. There are many options of varying kinds of tradeoffs.

I'm not very familiar with the input APIs, so not sure if there's some parameter you can just tweak to reduce the rate of calls - maybe just don't do anything unless the change in zoom is above dinner threshold, and then increase the threshold until the zooming doesn't lag?

Or you can send the zoom calls to another thread to actually invoke setParameters, and just drop a zoom call to the floor if that thread if already busy processing a previous call.

Or better, have a 'nextZoom' parameter that your zoom setting thread looks at once it finishes its prior call, and then just have the touch event handler update nextZoom on each invocation. The zoom setting thread then always checks if the value has changed once it finishes the last set call, and if so, sets it again.

Then you'll always get the newest zoom level, and they won't pile up either.

Eddy Talvala
  • 17,243
  • 2
  • 42
  • 47