Skip to content
Advertisement

CameraX: Animated Zoom

I am developing a camera app and I want to have something like double tap to zoom. I was able to implement that, but later I wanted to improve the app’s UX by animating the zoom. I tried applying a Ticker logic to do that but performing a simple zoom call from the CameraX API takes its own time (high enough to not be able to use it in a smooth animation. Is there any way I can animate the zoom from the current zoom value to the expected value?

Code:

            public boolean onDoubleTap(MotionEvent e) {
                Log.i(TAG, "===============Double tap detected.=========");

                final ZoomState zoomState = camera.getCameraInfo().getZoomState().getValue();
                float start, diff;

                if(zoomState!=null) {
                    start = zoomState.getZoomRatio();
                    diff = start * 0.5f;

                    final Calendar calendar = Calendar.getInstance();
                    final int ANIM_DURATION_IN_MS = 2000;
                    final long endTime = Calendar.getInstance().getTimeInMillis() + ANIM_DURATION_IN_MS;

                    double elapsed = 1.0;

                    while(elapsed>0.0) {
                        elapsed = endTime - Calendar.getInstance().getTimeInMillis();
                        double d = 1 - elapsed/(float)ANIM_DURATION_IN_MS;

                        Log.i(TAG, "getTime: " + Calendar.getInstance().getTimeInMillis());
                        Log.i(TAG, "endTime: " + endTime);
                        Log.i(TAG, "d: " + d);

                        try {
                            camera.getCameraControl().setZoomRatio((float) (start+(diff*d))).get();
                        } catch (ExecutionException | InterruptedException executionException) {
                            executionException.printStackTrace();
                        }
                        Log.i(TAG, "zoomRatio: " + (float) (start+diff*d));
                    }

                    Log.i(TAG, "Done");

                    camera.getCameraControl().setZoomRatio(start+diff);
                }

                return super.onDoubleTap(e);
            }

Advertisement

Answer

You can progressively change the zoom level to the desired zoom level in short timeframes to create this animation, but instead of using the zoom ratio, you can use the linear zoom in CameraX – that will give you a smooth transition, and it is easy to implement:

linearZoomSeekBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {        
    override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
        cameraControl.setLinearZoom(progress / 100f)
    }

    override fun onStartTrackingTouch(seekBar: SeekBar?) {}

    override fun onStopTrackingTouch(seekBar: SeekBar?) {}
})

This example is using a seek bar, but you can do this using a Value animator that changes its value automatically.

Example of a linear zoom value animator setup:

// Initializing the animator with values to zoom - min:0f - max:1f
ValueAnimator animator = ValueAnimator.ofFloat(0.1f, 0.2f, 0.3f, 0.4f, 0.5f);
// Setting animation duration
animator.setDuration(200);
// Adding listener for every value update of the animation
animator.addUpdateListener(valueAnimator -> camera.getCameraControl().setLinearZoom((float) valueAnimator.getAnimatedValue()));
// Start the zoom animation
animator.start();

The more values you’ll put in the initialization of the value animator, the smoother the animation will look.

User contributions licensed under: CC BY-SA
8 People found this is helpful
Advertisement