title: Gallery of images using ViewPager + zoom in ImageViews
body: <p><strong>What am I trying to implement?</strong></p>
  
  <p>A <em>gallery</em> of images using ViewPager. I choose this option because the smooth transition between images (I'm using ImageView), it is nice and quite easy to implement. </p>
  
  <p><strong>What is my problem exactly?</strong></p>
  
  <p>I've been able to implement all this <strong>but</strong> zoom isn't working. I can see in <em>LogCat</em> how it's printed <strong>ZOOM</strong> (the code is at the end of the post) but the image is not enlarged. Just a few notes about the following code:</p>
  
  <ul>
  <li><code>ImageViewHelperURL.setUrlDrawable((ImageView) img, url, R.drawable.no_image);</code> I'm using <a href="https://github.com/koush/UrlImageViewHelper" rel="noreferrer">UrlImageViewHelper</a> to download asynchronously the images from the web.</li>
  <li><code>api.getListUrls()</code> It's an ArrayList where I have the image urls.</li>
  <li><p>I've tried also using an ImageView from R.drawable instead of downloading the image</p>
  
  <pre><code>import android.content.Context;
  import android.content.Intent;
  import android.graphics.Matrix;
  import android.graphics.PointF;
  import android.os.Bundle;
  import android.support.v4.app.ActionBar;
  import android.support.v4.app.Fragment;
  import android.support.v4.app.FragmentActivity;
  import android.support.v4.app.FragmentManager;
  import android.support.v4.app.FragmentPagerAdapter;
  import android.support.v4.view.Menu;
  import android.support.v4.view.MenuItem;
  import android.support.v4.view.ViewPager;
  import android.util.FloatMath;
  import android.util.Log;
  import android.view.LayoutInflater;
  import android.view.MenuInflater;
  import android.view.MotionEvent;
  import android.view.View;
  import android.view.View.OnTouchListener;
  import android.view.ViewGroup;
  import android.view.ViewGroup.LayoutParams;
  import android.widget.Gallery;
  import android.widget.ImageView;
  import android.widget.Toast;
  
  public class Slide extends FragmentActivity {
      private ViewPager mPager;
      public static Api api;
      public static int POSITION;
      public static ActionBar topbar;
      public static Context ctx;
  
      @Override
      public void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.fragment);
          ctx = Slide.this;
          POSITION = 0;
          topbar = getSupportActionBar();
  
          /* get portadas */
          api = new Api();
          api.getUrlsFromAPI();
  
          topbar.setDisplayShowHomeEnabled(false);
          topbar.setDisplayShowTitleEnabled(true);
  
          mPager = (ViewPager) findViewById(R.id.pager);
          mPager.setAdapter(new TestAdapter(getSupportFragmentManager()));
      }
  
      @Override
      protected void onResume() {
          // TODO Auto-generated method stub
          super.onResume();
          mPager.setCurrentItem(POSITION);
      }
  
      static final class TestAdapter extends FragmentPagerAdapter {
          public TestAdapter(FragmentManager fm) {
              super(fm);
          }
  
          @Override
          public int getCount() {
              return api.getListUrls().size();
          }
  
          @Override
          public Fragment getItem(int position) {
              TestFragment f = new TestFragment();
  
              f.url = api.getListUrls().get(position).getUrl();
              f.position = position;
              return f;
          }
      }
  
      public static class TestFragment extends Fragment {
          String url = "";
          Integer position = 0;
  
          public TestFragment() {
              setRetainInstance(true);
          }
  
          @Override
          public void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setHasOptionsMenu(true);
          }
  
          @Override
          public View onCreateView(LayoutInflater inflater, ViewGroup container,
                  Bundle savedInstanceState) {
              ImageView img = new ImageView(getActivity());
  
              img.setPadding(6, 6, 6, 6) ;
              img.setLayoutParams(new Gallery.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT)) ;
  
              ImageViewHelperURL.setUrlDrawable((ImageView) img, url, R.drawable.no_image) ;
  
              img.setOnTouchListener(new OnTouchListener() {
                  private static final String TAG = "SlideImageView";
                  // These matrices will be used to move and zoom image
                  Matrix matrix = new Matrix();
                  Matrix savedMatrix = new Matrix();
  
                  // We can be in one of these 3 states
                  static final int NONE = 0;
                  static final int DRAG = 1;
                  static final int ZOOM = 2;
                  int mode = NONE;
  
                  // Remember some things for zooming
                  PointF start = new PointF();
                  PointF mid = new PointF();
                  float oldDist = 1f;
  
                  @Override
                  public boolean onTouch(View v, MotionEvent event) {
                      ImageView view = (ImageView) v;
  
                      // Dump touch event to log
                      dumpEvent(event);
  
                      // Handle touch events here...
                      switch (event.getAction() &amp; MotionEvent.ACTION_MASK) {
                      case MotionEvent.ACTION_DOWN:
                          savedMatrix.set(matrix);
                          start.set(event.getX(), event.getY());
                          Log.d(TAG, "mode=DRAG");
                          mode = DRAG;
                          break;
                      case MotionEvent.ACTION_POINTER_DOWN:
                          oldDist = spacing(event);
                          Log.d(TAG, "oldDist=" + oldDist);
                          if (oldDist &gt; 10f) {
                              savedMatrix.set(matrix);
                              midPoint(mid, event);
                              mode = ZOOM;
                              Log.d(TAG, "mode=ZOOM");
                          }
                          break;
                      case MotionEvent.ACTION_UP:
                      case MotionEvent.ACTION_POINTER_UP:
                          mode = NONE;
                          Log.d(TAG, "mode=NONE");
                          break;
                      case MotionEvent.ACTION_MOVE:
                          if (mode == DRAG) {
                              // ...
                              matrix.set(savedMatrix);
                              matrix.postTranslate(event.getX() - start.x,
                                      event.getY() - start.y);
                          } else if (mode == ZOOM) {
                              float newDist = spacing(event);
                              Log.d(TAG, "newDist=" + newDist);
                              if (newDist &gt; 10f) {
                                  matrix.set(savedMatrix);
                                  float scale = newDist / oldDist;
                                  Log.d(TAG, "ZOOOOOOOM: " + scale);
                                  matrix.postScale(scale, scale, mid.x, mid.y);
                              }
                          }
                          break;
                      }
  
                      view.setImageMatrix(matrix);
                      return true; // indicate event was handled
                  }
  
                  /** Show an event in the LogCat view, for debugging */
                  private void dumpEvent(MotionEvent event) {
                      String names[] = { "DOWN", "UP", "MOVE", "CANCEL",
                              "OUTSIDE", "POINTER_DOWN", "POINTER_UP", "7?",
                              "8?", "9?" };
                      StringBuilder sb = new StringBuilder();
                      int action = event.getAction();
                      int actionCode = action &amp; MotionEvent.ACTION_MASK;
                      sb.append("event ACTION_").append(names[actionCode]);
                      if (actionCode == MotionEvent.ACTION_POINTER_DOWN
                              || actionCode == MotionEvent.ACTION_POINTER_UP) {
                          sb.append("(pid ").append(
                                  action &gt;&gt; MotionEvent.ACTION_POINTER_ID_SHIFT);
                          sb.append(")");
                      }
                      sb.append("[");
                      for (int i = 0; i &lt; event.getPointerCount(); i++) {
                          sb.append("#").append(i);
                          sb.append("(pid ").append(event.getPointerId(i));
                          sb.append(")=").append((int) event.getX(i));
                          sb.append(",").append((int) event.getY(i));
                          if (i + 1 &lt; event.getPointerCount())
                              sb.append(";");
                      }
                      sb.append("]");
                      Log.d(TAG, sb.toString());
                  }
  
                  /** Determine the space between the first two fingers */
                  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 mid point of the first two fingers */
                  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);
                  }
              });
  
              return img;
          }
  
          @Override
          public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
  
          }
  
          @Override
          public boolean onOptionsItemSelected(MenuItem item) {
  
              return super.onOptionsItemSelected(item);
          }
      }
  
  }
  </code></pre></li>
  </ul>
  
  <p>I've already tried the following tutorial with no success:</p>
  
  <ul>
  <li><a href="http://www.zdnet.com/blog/burnette/how-to-use-multi-touch-in-android-2-part-6-implementing-the-pinch-zoom-gesture/1847" rel="noreferrer">How to use Multi-touch in Android 2: Part 6, Implementing the Pinch Zoom Gesture</a></li>
  </ul>