ImageView Zoom and Scroll

by Alessandro Crugnola on April 4, 2011

in android

As long as Android doesn’t have a built-in ImageView widget with zoom and scroll capabilities I tries to create one by myself starting from the google repository.

The result is pretty nice so I’m posting here the source code, if anyone is interested, or simply doesn’t want to waste the time creating a new one.

Here’s a sample code on how to use it in an Activity:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
package it.sephiroth.android.demo;

import it.sephiroth.android.library.imagezoom.ImageViewTouch;

import java.io.IOException;

import android.app.Activity;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore.Images;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Toast;

public class ImageZoomActivity extends Activity {
   
   private ImageViewTouch  mImageView;
   
   @Override
   protected void onCreate( Bundle savedInstanceState )
   {
      super.onCreate( savedInstanceState );
     
      requestWindowFeature( Window.FEATURE_NO_TITLE );
      setContentView( R.layout.main );
      getWindow().addFlags( WindowManager.LayoutParams.FLAG_FULLSCREEN );
      selectRandomImage();
   }
   
   @Override
   public void onContentChanged()
   {
      super.onContentChanged();
      mImageView = (ImageViewTouch)findViewById( R.id.imageView1 );
   }
   
   /**
    * pick a random image from your library
    * and display it
    */

   public void selectRandomImage()
   {
      Cursor c = getContentResolver().query( Images.Media.EXTERNAL_CONTENT_URI, null, null, null, null );
      if ( c != null ) {
         int count = c.getCount();
         int position = (int)( Math.random() * count );
         if ( c.moveToPosition( position ) ) {
            long id = c.getLong( c.getColumnIndex( Images.Media._ID ) );
            int orientation = c.getInt( c.getColumnIndex( Images.Media.ORIENTATION ) );
           
            Uri imageUri = Uri.parse( Images.Media.EXTERNAL_CONTENT_URI + "/" + id );
            Bitmap bitmap;
            try {
               bitmap = ImageLoader.loadFromUri( this, imageUri.toString(), 1024, 1024 );
               mImageView.setImageBitmapReset( bitmap, orientation, true );
            }
            catch ( IOException e ) {
               Toast.makeText( this, e.toString(), Toast.LENGTH_LONG ).show();
            }
         }
         c.close();
         c = null;
         return;
      }
   } 
}

 

 

Anyway, if you want to download the source, here is the eclipse source project:
http://blog.sephiroth.it/wp-…/ImageZoom.zip

  • http://www.facebook.com/cliffus Cliff Ophalvens

    Hi!

    great library! Thanks a lot!

    I noticed this library wasn’t working on Android 2.1, because of the API level (8) for the gesture recognizers.

    I ported the classes by downloading the source code from http://grepcode.com/search?query=ScaleGestureDetector

    The following classed need to be added to your library:
    - ScaleGestureDetector
    - ViewConfiguration
    - GestureDetector

    By adjusting some constants (like MotionEvent.ACTION_POINTER_INDEX_SHIFT => MotionEvent.ACTION_POINTER_ID_SHIFT,…) everything works like a charm!

    Grtz
    Cliff

    • Patrick Dumenil

      Could you post the modified code? Thanks

    • Esteban Flores

      Molto bene alessandro!

      I tryed, like cliff says, to replace those classes and constanst and now the proyect compiles fine! But I receive an exception on 2.1 phones!

      java.lang.NoSuchMethodError: android.view.ScaleGestureDetector$SimpleOnScaleGestureListener.

      I tryed to add a constructor without parameters but nothing happend!

      Any ideas?

      Esteban Flores

  • Eyal

    How can I avoid the automaticly scale down of the image?

  • Eyal

    How can I use “wrap_content” for hight and width of ImageViewTouch?

  • Vineet Billorey

    Hi,

    It doesn’t run in my emulator/nexus S

    Only a blank screen.

    Thanks.

    vineet.billorey@alexiatechnologeis.com

  • http://pulse.yahoo.com/_DENNH7GEYWLMNL2WY4Y5YIWSTE nisha

    Hey thanks a lot…Very helpful tutorial…

  • Ragummrsa

    Very very good job. its working fine but one problem that is I have some images in custom gallery view it display when i use ur custom image view to adapter class the gallery view scrolling not working. only one image was displayed. how to implement to scroll the gallery view. please share ur ideas with me. I’m new one for android and mobile technologies.

  • Bruno

    Hy, I’m using Android 3.0 and trying to use your library, but as soon as I tap the image with two fingers, it simply disappears… any idea on what is going on?

  • Dhaiwat Bhavsar

    hi can you provide me direction how to run on 2.1 plz

    • Ragummrsa

      sorry i think i cant run 2.1 it should only run from 2.2 and above. because ScaleGestureDetector.SimpleOnScaleGestureListener support only 2.2 and above..

  • Lee LeOn

    wow, that is great!!

  • Lee LeOn

    I modify the ImageViewTouch.java code for android 2.1 and success work it.

    package it.sephiroth.android.library.imagezoom;

    import android.content.Context;
    import android.graphics.PointF;
    import android.util.AttributeSet;
    import android.util.FloatMath;
    import android.view.GestureDetector;
    import android.view.MotionEvent;
    import android.view.ViewConfiguration;

    public class ImageViewTouch extends ImageViewTouchBase{

    protected static final float MIN_DIST = 10F;

    static final float MIN_ZOOM = 0.9f;
    protected GestureDetector mGestureDetector;
    protected int mTouchSlop;
    protected float mCurrentScaleFactor;
    protected float mScaleFactor;
    protected int mDoubleTapDirection;
    protected GestureListener mGestureListener;

    PointF start = new PointF();
    PointF mid = new PointF();
    float oldDist;

    private final static int NONE = 0;
    private final static int DRAG = 1;
    private final static int ZOOM = 2;

    private int touchState = NONE;

    public ImageViewTouch( Context context, AttributeSet attrs )
    {
    super( context, attrs );
    }

    @Override
    protected void init()
    {
    super.init();
    mTouchSlop = ViewConfiguration.getTouchSlop();
    mGestureListener = new GestureListener();

    mGestureDetector = new GestureDetector(getContext(), mGestureListener);
    mCurrentScaleFactor = 1f;
    mDoubleTapDirection = 1;
    }

    @Override
    public void setImageRotateBitmapReset( RotateBitmap bitmap, boolean reset )
    {
    super.setImageRotateBitmapReset( bitmap, reset );
    mScaleFactor = getMaxZoom() / 3;
    }

    @Override
    public boolean onTouchEvent( MotionEvent event )
    {
    if (touchState != ZOOM) mGestureDetector.onTouchEvent( event );
    int action = event.getAction();
    switch (action & MotionEvent.ACTION_MASK) {
    case MotionEvent.ACTION_DOWN:
    start.set(event.getX(), event.getY());
    touchState = DRAG;
    break;
    case MotionEvent.ACTION_UP:
    touchState = NONE;
    if ( getScale() MIN_DIST) {
    touchState = ZOOM;
    midPoint(mid, event);
    }
    break;
    case MotionEvent.ACTION_MOVE:
    if (touchState == ZOOM) {
    onScale (event);
    }
    break;
    }
    return true;
    }

    // calculate the distance
    private float spacing(MotionEvent event) {
    float x = event.getX(0) – event.getX(1);
    float y = event.getY(0) – event.getY(1);
    return FloatMath.sqrt(x * x + y * y);
    }

    // calculate the center point
    private void midPoint(PointF point, MotionEvent event) {
    float x = event.getX(0) + event.getX(1);
    float y = event.getY(0) + event.getY(1);
    point.set(x / 2, y / 2);
    }

    public boolean onScale( MotionEvent event )
    {
    float span = spacing(event);
    float targetScale = span / oldDist;
    if (span > MIN_DIST) {
    targetScale = Math.min( getMaxZoom(), Math.max( targetScale, MIN_ZOOM ) );
    zoomTo( targetScale, mid.x, mid.y);
    mCurrentScaleFactor = Math.min( getMaxZoom(), Math.max( targetScale, MIN_ZOOM ) );
    mDoubleTapDirection = 1;
    invalidate();
    return true;
    }
    return false;
    }

    @Override
    protected void onZoom( float scale )
    {
    super.onZoom( scale );
    mCurrentScaleFactor = scale;
    }

    protected float onDoubleTapPost( float scale, float maxZoom )
    {
    if ( mDoubleTapDirection == 1 ) {
    if ( ( scale + ( mScaleFactor * 2 ) ) 800 || Math.abs( velocityY ) > 800 ) {
    scrollBy( diffX / 2, diffY / 2, 300 );
    invalidate();
    }
    return super.onFling( e1, e2, velocityX, velocityY );
    }
    }
    }

  • Lee LeOn

    I found a more simple method to solve the problem in android2.1 . We can copy the ScaleGestureDetector.java, we can found it in android 2.2 open source($ANDROID_SRE/frameworks/base/core/java/android/view/ScaleGestureDetector.java), to our project.And modify some attributes.~~ ^^

  • Dynde

    I have the same problem as bruno with android 3.x. Image displays fine, but as soon as I double touch it, the image disappears?

    • Dynde

      I figured it out – you need to use the setImageBitmapReset methods, so it sets all the variables (like maxzoom etc.) – I wonder why the regular imageview method “setImageBitmap” wasn’t overriden, to make sure it always goes through the reset?

  • http://www.facebook.com/bigdragon13th Bigdragon Thunder

    How can I modify this to load image from URL of the website??

    • http://www.facebook.com/bigdragon13th Bigdragon Thunder

      Never mind, I’ve figured it out.

      • M040980

        You got any sample code how to load the image from url? I can’t figure it out.

  • Sisthein

    really cool library. but now i want to draw a circle or rectangle or what ever on a double tap. so i put a canvas around the member variable mBitmap inside the RotateBitmap class. i added a getter for the canvas and tried to draw a circle on the canvas in the method onDoubleTapPost() in the class ImageViewTouch. but the circle isnt visible :-(

    any idea what is wrong?

  • Rolf

    How can I use this library in a TabHost? I liked to put in each tab another picture

  • Arifandalusia

    Hello .how do I change the select random image to the image that i want. please give some snippet code. tq

  • Anonymous

    Good article!

  • Tek Yin Kwee

    Hi, how to make the bitmap automatically fitwidth at first load?

  • Haddellp

    This is a great example and works perfectly. I was just wondering how you change it from a random picture to a pre-determined picture in the drawable folder?

    Many Thnaks

  • IC92

    hai..
    thanks for your code..
    may i use this on my project?
    my project is such a maps application, which based on a picture file..
    so i need that picture zoom in and out

    • http://www.sephiroth.it Alessandro Crugnola

      Yes indeed

      • ic92

        hai..
        thanks for the code,, it is work good!!
        however, i got problem when loading image, i change your code arround so i can load the image that i want based on location that i give. the picture is in 300 dpi, png format. it is always succes for the first load. however, when i try to point to another file, it is crashed and say “java.lang.OutOfMemoryError: bitmap size exceeds VM budget.”
        here is my code to load the image:

        private Bitmap loadFile(String region, String name) {
        FileInputStream fis;
        BufferedInputStream Stream;
        Bitmap bmp = null;

        String file = Environment.getExternalStorageDirectory()+”/region+”/”+name;
        try {
        fis = new FileInputStream(file);
        Stream = new BufferedInputStream(fis,16384);
        bmp = BitmapFactory.decodeStream(Stream);
        }
        catch (FileNotFoundException e) {
        e.printStackTrace();
        }
        return bmp;

        }

        do you have any suggestion?

  • Anonymous

    hai……….
    i am getting just blank screen and how i need to import my drawable image.

  • http://www.facebook.com/ye.wangxing Ye Wangxing

    thanks a lot. it is useful

  • Janu Manu Hu 11

    Hi……….
    i am getting just blank screen… :(

Previous post:

Next post: