6

I'm using Android Studio to display an imageView. I'm using pinch zoom to interact with my ImageView.

Code:

private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener{
    @Override
    public boolean onScale(ScaleGestureDetector detector) {
        scale = scale * detector.getScaleFactor();
        scale = Math.max(0.1f, Math.min(scale, 5f));
        matrix.setScale(scale, scale);

        imageView.setImageMatrix(matrix);
        return true;
    }
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    scaleGestureDetector.onTouchEvent(event);
    return true;
}

Zoom is fine, but problem is the position of imageview, it's stuck in left upper corner. Tried layout changes but nothing to do. After some reseaches, I've seen these links in the forum ImageView Center in position with ScaleType Matrix and Center the image in ImageView after zoom-pinch, but these solutions aren't working, I've also checked the links given inside.

Help would be appreciated,

Thanks !

EDIT: Added the piece of code on how I get my ImageView

Picasso.with(this).load(url).resize(350, 330).centerInside().into(imageView);

onCreate Code

onCreate

ScaleListner Class and Gesture Code

listener

Community
  • 1
  • 1
Jay
  • 144
  • 1
  • 2
  • 14

1 Answers1

11
    Picasso.with(this).load(url).into(imageView, new Callback.EmptyCallback() {
        @Override
        public void onSuccess() {
            Drawable d = imageView.getDrawable();
            // TODO: check that d isn't null

            RectF imageRectF = new RectF(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
            RectF viewRectF = new RectF(0, 0, imageView.getWidth(), imageView.getHeight());
            matrix.setRectToRect(imageRectF, viewRectF, ScaleToFit.CENTER);
            imageView.setImageMatrix(matrix);
        }
    });

Edit 2:

How to center the image like CENTER_INSIDE but using matrix:

First we need a rectangle with the image dimensions:

    Drawable d = imageView.getDrawable();
    // TODO: check that d isn't null

    RectF imageRectF = new RectF(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());

Next you need a rectangle with the view dimensions:

    RectF viewRectF = new RectF(0, 0, imageView.getWidth(), imageView.getHeight());

Now we run a method on matrix that will center the image in the view:

    matrix.setRectToRect(imageRectF, viewRectF, ScaleToFit.CENTER);

What this does is set up the matrix so that the first rectangle will transform to the second rectangle. ScaleToFit.CENTER will preserve the aspect ratio and have the same effect as scale type CENTER_INSIDE.

So if you call

    imageView.setImageMatrix(matrix);

at this point, you will have a centered image.


Edit: I think you are almost there.

Your matrix will undo the image centering that Picasso did, so you need to put in a translation to center the image before you scale it.

    @Override
    public boolean onScale(ScaleGestureDetector detector) {

        Drawable d = imageView.getDrawable();
        // if d is null, then Picasso hasn't loaded the image yet

        float offsetX = (imageView.getWidth() - d.getIntrinsicWidth()) / 2F;
        float offsetY = (imageView.getHeight() - d.getIntrinsicHeight()) / 2F;

        float centerX = imageView.getWidth() / 2F;
        float centerY = imageView.getHeight() / 2F;

        // note that these offset and center values don't change with the scaling, 
        // so you can calculate them somewhere else and then use them here.

        scale *= detector.getScaleFactor();
        scale = Math.max(0.1f, Math.min(scale, 5f));

        matrix.setScale(scale, scale, centerX, centerY);
        matrix.preTranslate(offsetX, offsetY);

        imageView.setImageMatrix(matrix);
    }

You are using setScale(float sx, float sy). There is another version, setScale(float sx, float sy, float px, float py) where px,py is a pivot point.

So if you want to center your image, determine the center of your view and use the x,y value as the pivot point.

You will also want to center the image inside the view, so you will need to move the image first before you scale.

    float offsetX = (imageView.getWidth() - bitmap.getIntrinsicWidth()) / 2F;
    float offsetY = (imageView.getHeight() - bitmap.getIntrinsicHeight()) / 2F;

    float centerX = imageView.getWidth() / 2F;
    float centerY = imageView.getHeight() / 2F;

    matrix.setScale(scale, scale, centerX, centerY);
    matrix.preTranslate(offsetX, offsetY);
kris larson
  • 30,387
  • 5
  • 62
  • 74
  • Thank you for your answer I'm trying it as soon as I can ! – Jay May 18 '16 at 07:08
  • Having some errors with variables view, image (which i tried to replace), and it doesn't know matrix.preTransform – Jay May 18 '16 at 07:29
  • 1
    Should have been `preTranslate`, updated my answer. You can leave off the `preTranslate` method just to see the image zoom without being stuck in the upper left hand corner. But I'm betting your image isn't centered, so you will need a translation in there somewhere to center the image in the view. – kris larson May 18 '16 at 14:32
  • `view` should have been `imageView`. You didn't include any code for how you are getting the actual bitmap, so I just called it `bitmap`. The main point is that you will need the dimensions of the bitmap as well as the dimensions of the `ImageView` in order to center the bitmap so the scaling looks right. – kris larson May 18 '16 at 14:37
  • I updated my code, in fact, I'm using Picasso with a URL passed from an other activity to populate my imageview, thanks for your help ! Im not using directly a bitmap, how can I do it ? – Jay May 18 '16 at 15:40
  • Ah. So you don't need the `preTranslate` as Picasso is doing the centering for you. So does adding the pivot point to the scaling make it work? – kris larson May 18 '16 at 15:45
  • My imageview is still in the left upper corner, but when I zoom it gets out of the view, code updated – Jay May 18 '16 at 15:58
  • 1
    Okay, I think I know what's going on. So Picasso is centering the image, but as soon as you apply the matrix to the `ImageView`, it goes back to the upper left corner? – kris larson May 18 '16 at 16:25
  • Yes, I can't see it that much but yes it is. – Jay May 23 '16 at 07:49
  • First of all thank you for this huge help, yes I'm almost there. Here is the situation with the updated answer. I have touched the imageview, its beginning position is in the upper left corner, then when I zoom, it places itself in the center of the view and stays there. Tried to make it centered at launch of activity but failed. Any idea ? Sorry for bothering – Jay May 24 '16 at 08:20
  • So once you start zooming everything's okay but the image is in wrong place to start? – kris larson May 24 '16 at 08:26
  • This is exactly what's happening yes – Jay May 24 '16 at 08:27
  • Sorry still not working, I updated my screeshot class to show you – Jay May 24 '16 at 09:03
  • That second bit of code was not for the `onScale` method. You said the image was in the wrong place to start. Once the image has been loaded, you can use that code to center the image when you are not scaling. – kris larson May 24 '16 at 09:09
  • My bad, I've put it in my onCreate method, so I passed the Drawable d declaration out of scope from my ScaleListener class, so I can use it in onCreate and onScale method. I have a NullPointerException, which I expected --> "Attempt to invoke virtual method 'int android.graphics.drawable.Drawable.getIntrinsicWidth()' on a null object reference". But I don't really know what to put from here – Jay May 24 '16 at 09:19
  • No, it wouldn't be `onCreate`. Earlier you said, "I have touched the imageview, its beginning position is in the upper left corner". I'm trying to understand how Picasso is centering the image, yet the image is getting reset to (0,0) before you zoom it. Are you calling `imageView.setImageMatrix()` anywhere else? If so, you should post that section of code. Are you also using a `GestureDetector`? That listener code should be posted as well. – kris larson May 24 '16 at 09:31
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/112765/discussion-between-kris-larson-and-jay). – kris larson May 24 '16 at 09:39
  • Thanks for you help, it is the perfect solution with Picasso ! Accepted your answer – Jay May 24 '16 at 10:01