Android Gallery with Pan/Zoom ImageView

2015-03-06 update: As some of the reference links below no longer exist, I have published my source codes in GitHub for perusal.

I was working on an image gallery project whereby the gallery has its own album of pictures, is side-scrolling and allows zooming and panning of each image; just like the built-in gallery in an Android phone.

After more than a week of hair-pulling and eye popping googling, I managed to find the list of resources to display pictures using the Android gallery widget and the codes of panning and zooming a single image. However, I was left with two issues to resolve, which I did below:

  1. How to differentiate which touch movements belong to the gallery and which ones belong to the image views?
  2. How to, somewhat seamlessly, switch an image view from a scale type of CENTER_INSIDE to MATRIX for zooming?

Before I explain what I did, please try out the gallery tutorial in developer.android.com and modify the xml to display the gallery full-screen. Hint: fill_parent…

First up, create your own ImageView class by extending Android’s and adapt the pan/zoom codes given in [6]. You may make use of the TouchImageView class which basically has the same implementation but I prefer to learn from following the tutorial.

Why creating our own MyImageView class and not create a TouchListener to be set in ImageView? It is because we need to include some custom attributes to control the touch rights. Note that we allow initial setting of matrices to prevent the abrupt jump in display size when we switch scale types.

public class MyImageView extends ImageView {
    boolean isDraggable = false;
    boolean isRight = false;
    boolean isLeft = false;

    // These matrices will be used to move and zoom image
    Matrix matrix = new Matrix();
    Matrix savedMatrix = new Matrix();

    public void setMatrix(Matrix m) {
        matrix.set(m);
    }

    public void setSavedMatrix(Matrix m) {
        savedMatrix.set(m);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (isDraggable) {
            // place pan/zoom codes here
        }
        return true;
    }
}

Look at the comments section of [6] and you will find the codes to adding a limit to the distance one can pan the image when the image is bigger than the view. This is set to the border of the image and thus allow us to return control to the gallery for scrolling. Add the following codes at the end:

if (dx == 0) {
    if (event.getX() - start.x < 0)
        isRight = true;
    else if (event.getX() - start.x > 0)
        isLeft = true;
}
else {
    isRight = false;
    isLeft = false;
}

Now back to the gallery. Google gave me numerous hints to intercepting touch events to the gallery and control which view processes what events. I could not find any concrete sample codes but after some trial-and-error tries, I came up with the following:

public class MyGallery extends Gallery {
    private PointF m_start = new PointF();
    private MyImageView imageView;

    public MyGallery(Context context) {
        super(context);
    }

    public MyGallery(Context context, AttributeSet attrSet) {
        super(context, attrSet);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        imageView = (MyImageView) getSelectedView();
        switch (event.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN:
                m_start.set(event.getX(), event.getY());
                break;
            case MotionEvent.ACTION_POINTER_DOWN:
                imageView.isDraggable = true;
                if (imageView.getScaleType() != ImageView.ScaleType.MATRIX) {
                    imageView.setMatrix(imageView.getImageMatrix());
                    imageView.setScaleType(ImageView.ScaleType.MATRIX);
                }
                break;
            case MotionEvent.ACTION_MOVE:
                if ((event.getX() - m_start.x < 0 && imageView.isRight) ||
                    (event.getX() - m_start.x > 0 && imageView.isLeft))
                    imageView.isDraggable = false;
                break;
        }
        if (!imageView.isDraggable) {
            onTouchEvent(event);
        }
        return super.onInterceptTouchEvent(event);
    }
}

References:

  1. http://www.eoeandroid.com/thread-101038-1-1.html
  2. http://stackoverflow.com/questions/7441114/image-view-zoom-in-and-out-inside-gallery-view-in-android
  3. http://stackoverflow.com/questions/3171452/scrollview-and-gallery-interfering
  4. http://twnin.blogspot.com/2011/04/extend-gallery-support.html
  5. http://stackoverflow.com/questions/6075363/android-image-view-matrix-scale-translate
  6. http://blogs.zdnet.com/Burnette/?p=1847

Acknowledgement:

Disclaimer:

This solution should only be considered to be a ‘pseudo-solution’ as it mimics the usual album gallery app in an Android phone but nowhere as smooth as it. If anyone is kind enough to share (privately or publicly) with me how the phone’s gallery app is achieved, it will be greatly appreciated.

This entry was posted in Program Coding and tagged . Bookmark the permalink.

4 Responses to Android Gallery with Pan/Zoom ImageView

  1. Rash011 says:

    I’m in stuck with Gallery( Pan/Zoom ImageView) and I’ve tried much in different way. Can you pls give me your gallery work of android?

  2. Hi Rash,

    I don’t like to just give my codes away without explanation. I prefer you tell me the problems you are facing and we can work them out for the benefits of other developers. Someone may have a better solution than I do.

    Feel free to discuss here.

  3. arjun says:

    can you add a project src download link please

Leave a Reply

Your email address will not be published. Required fields are marked *