Android zoom image from thumb to center

I am following the following tutorial to zoom an image from thumb in Android http://developer.android.com/training/animation/zoom.html

Everything works great except that I would like the zoomed image to be centered in the view and have a maximum size (not fill_parent or match_parent as in the tutorial). I have identical code but my XML is different to try to center the image, but It does not work. What is the problem?

<FrameLayout.....
<RelativeLayout
    android:id="@+id/te"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <ImageView
        android:id="@+id/memory_expanded_image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:maxHeight="150dp"
        android:maxWidth="150dp"
        android:adjustViewBounds="true"
        android:layout_centerInParent="true"
        android:gravity="center"
        android:scaleType="fitCenter"
        android:visibility="invisible"
        android:contentDescription="@string/description_zoom_touch_close" />

</RelativeLayout>
</FrameLayout>

Part of the zoom code (identical to tutorial). I think I need to change something here, the finalBounds but I could not figure it out.

// Calculate the starting and ending bounds for the zoomed-in image.
// This step involves lots of math. Yay, math.
final Rect startBounds = new Rect();
final Rect finalBounds = new Rect();
final Point globalOffset = new Point();

// The start bounds are the global visible rectangle of the thumbnail,
// and the final bounds are the global visible rectangle of the container
// view. Also set the container view's offset as the origin for the
// bounds, since that's the origin for the positioning animation
// properties (X, Y).
thumbView.getGlobalVisibleRect(startBounds);
findViewById(R.id.container)
        .getGlobalVisibleRect(finalBounds, globalOffset);
startBounds.offset(-globalOffset.x, -globalOffset.y);
finalBounds.offset(-globalOffset.x, -globalOffset.y)

You need to modify the finalBounds to match the actual size of the image. Something like this

int imageHeight = expandedImageView.getHeight();
int imageWidth = expandedImageView.getWidth();
int horizontalMargin = 0,  verticalMargin = 0;
if (imageHeight < finalBounds.height()) {
    verticalMargin = (finalBounds.height() / 2) - (imageHeight / 2);
}
if (imageWidth < finalBounds.width()) {
    horizontalMargin = (finalBounds.width() / 2) - (imageWidth / 2);
}
finalBounds.set(finalBounds.left + horizontalMargin, finalBounds.top + verticalMargin, finalBounds.right - horizontalMargin, finalBounds.bottom - verticalMargin);

Full code:

Layout:

<Framelayout
...
...
<ImageView
   android:id="@+id/memory_expanded_image"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:contentDescription="@string/description_zoom_touch_close"
   android:visibility="invisible"/>

Activity:

private void zoomImageFromThumb(final View thumbView, int imageResId) {
        // If there's an animation in progress, cancel it immediately and proceed with this one.
        if (mCurrentAnimator != null) {
            mCurrentAnimator.cancel();
        }

        // Load the high-resolution "zoomed-in" image.
        final ImageView expandedImageView = (ImageView) findViewById(R.id.memory_expanded_image);
        expandedImageView.setImageResource(imageResId);

        // Calculate the starting and ending bounds for the zoomed-in image. This step
        // involves lots of math. Yay, math.
        final Rect startBounds = new Rect();
        final Rect finalBounds = new Rect();
        final Point globalOffset = new Point();

        // The start bounds are the global visible rectangle of the thumbnail, and the
        // final bounds are the global visible rectangle of the container view. Also
        // set the container view's offset as the origin for the bounds, since that's
        // the origin for the positioning animation properties (X, Y).
        thumbView.getGlobalVisibleRect(startBounds);
        findViewById(R.id.container).getGlobalVisibleRect(finalBounds, globalOffset);
        startBounds.offset(-globalOffset.x, -globalOffset.y);
        finalBounds.offset(-globalOffset.x, -globalOffset.y);

        //modify the final rect to match actual size of the image
        int imageHeight = expandedImageView.getHeight();
        int imageWidth = expandedImageView.getWidth();
        int horizontalMargin = 0,  verticalMargin = 0;
        if (imageHeight < finalBounds.height()) {
            verticalMargin = (finalBounds.height() / 2) - (imageHeight / 2);
        }
        if (imageWidth < finalBounds.width()) {
            horizontalMargin = (finalBounds.width() / 2) - (imageWidth / 2);
        }
        finalBounds.set(finalBounds.left + horizontalMargin, finalBounds.top + verticalMargin, finalBounds.right - horizontalMargin, finalBounds.bottom - verticalMargin);

        // Adjust the start bounds to be the same aspect ratio as the final bounds using the
        // "center crop" technique. This prevents undesirable stretching during the animation.
        // Also calculate the start scaling factor (the end scaling factor is always 1.0).
        float startScale;
        if ((float) finalBounds.width() / finalBounds.height()
                > (float) startBounds.width() / startBounds.height()) {
            // Extend start bounds horizontally
            startScale = (float) startBounds.height() / finalBounds.height();
            float startWidth = startScale * finalBounds.width();
            float deltaWidth = (startWidth - startBounds.width()) / 2;
            startBounds.left -= deltaWidth;
            startBounds.right += deltaWidth;
        } else {
            // Extend start bounds vertically
            startScale = (float) startBounds.width() / finalBounds.width();
            float startHeight = startScale * finalBounds.height();
            float deltaHeight = (startHeight - startBounds.height()) / 2;
            startBounds.top -= deltaHeight;
            startBounds.bottom += deltaHeight;
        }

        // Hide the thumbnail and show the zoomed-in view. When the animation begins,
        // it will position the zoomed-in view in the place of the thumbnail.
        thumbView.setAlpha(0f);
        expandedImageView.setVisibility(View.VISIBLE);

        // Set the pivot point for SCALE_X and SCALE_Y transformations to the top-left corner of
        // the zoomed-in view (the default is the center of the view).
        expandedImageView.setPivotX(0f);
        expandedImageView.setPivotY(0f);

        // Construct and run the parallel animation of the four translation and scale properties
        // (X, Y, SCALE_X, and SCALE_Y).
        AnimatorSet set = new AnimatorSet();
        set
                .play(ObjectAnimator.ofFloat(expandedImageView, View.X, startBounds.left,
                        finalBounds.left))
                .with(ObjectAnimator.ofFloat(expandedImageView, View.Y, startBounds.top,
                        finalBounds.top))
                .with(ObjectAnimator.ofFloat(expandedImageView, View.SCALE_X, startScale, 1f))
                .with(ObjectAnimator.ofFloat(expandedImageView, View.SCALE_Y, startScale, 1f));
        set.setDuration(mShortAnimationDuration);
        set.setInterpolator(new DecelerateInterpolator());
        set.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                mCurrentAnimator = null;
            }

            @Override
            public void onAnimationCancel(Animator animation) {
                mCurrentAnimator = null;
            }
        });
        set.start();
        mCurrentAnimator = set;

        // Upon clicking the zoomed-in image, it should zoom back down to the original bounds
        // and show the thumbnail instead of the expanded image.
        final float startScaleFinal = startScale;
        expandedImageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (mCurrentAnimator != null) {
                    mCurrentAnimator.cancel();
                }

                // Animate the four positioning/sizing properties in parallel, back to their
                // original values.
                AnimatorSet set = new AnimatorSet();
                set
                        .play(ObjectAnimator.ofFloat(expandedImageView, View.X, startBounds.left))
                        .with(ObjectAnimator.ofFloat(expandedImageView, View.Y, startBounds.top))
                        .with(ObjectAnimator
                                .ofFloat(expandedImageView, View.SCALE_X, startScaleFinal))
                        .with(ObjectAnimator
                                .ofFloat(expandedImageView, View.SCALE_Y, startScaleFinal));
                set.setDuration(mShortAnimationDuration);
                set.setInterpolator(new DecelerateInterpolator());
                set.addListener(new AnimatorListenerAdapter() {
                    @Override
                    public void onAnimationEnd(Animator animation) {
                        thumbView.setAlpha(1f);
                        expandedImageView.setVisibility(View.GONE);
                        mCurrentAnimator = null;
                    }

                    @Override
                    public void onAnimationCancel(Animator animation) {
                        thumbView.setAlpha(1f);
                        expandedImageView.setVisibility(View.GONE);
                        mCurrentAnimator = null;
                    }
                });
                set.start();
                mCurrentAnimator = set;
            }
        });
    }

Related Articles
  • I am making an application in which i'm using camera function of android. I'm opening camera and then taking picture.In Simple way its easy to do. But i want to take picture by camera when user touch on anywhere on opened camera screen. (Like we use
  • In my application i want to drag the image and zoom the image.So that i followed the bellow link. http://www.androidhub4you.com/2013/05/zoom-image-demo-in-android-zoom-image.html By using this every thing is working good. But my requirement is when e
  • I'm using BitmapFactory.decodeStream to load an image from a url in Android. I want to only download images below a certain size, and I'm currently using getContentLength to check this. However, I'm told that getContentLength doesn't always provide t
  • I am making a project in which i want to select multiple photos from gallery and want to save that in imageview array. I am able to import single image and save at imageview Can anyone tell please how may i import multiple images and save in array or
  • i need to capture image from required portion of the screen. capture image from camera. at that time other screen content as it is. how is this possible? try to use Surface View for creating dynamic camera view and set in your required portion. follo
  • I have application where images downloads from internet (arrays.xml) and then shown in Pager Adapter consequentially. I need to set the desired image to android wallpaper with help button. But i don't understand how add image from cache-memory to wal
  • I've tried answers from other similar stackoverflow questions, but cannot figure out what i am doing wrong. I have an sqlite database which includes several columns, one of which is the filename of a png file stored in res/drawable. I can populate my
  • I am trying to create a zoom animation for a view. I want the animation from the centre of the view for the custom scale. Tried following three approaches but none seems to work (1) Got some ideas from http://developer.android.com/training/animation/
  • I am using Android to send data to d3.js webview in JSON format. I have faced a problem. Here I have a d3.js code like this. I have attached the example of this code so that it can be run. https://drive.google.com/file/d/0B7Ztdu46v0uOZjhvTG5HRlVRRG8/
You Might Also Like