Monday, July 30, 2012

Android: Swipe Image Viewer

EDIT: I have a much simpler implementation with ViewPager, and the github project has been updated. See post here.


I have a GrideView of images, which enlarges to full screen when you tap on any image. When I showed it to my friend he swiped to get to the next image, but that did not do anything because I was just using a plain old ImageView. I looked around for a standard widget to do that, and couldn't find any. So I unwillingly rolled my own solution: http://github.com/chiuki/android-swipe-image-viewer.

I show the image in an ImageSwitcher. It contains two views, one displays the current image, and the other one holds the image to swap in. I lifted the gesture listener code from the Android Gallery app:

private class SwipeListener extends SimpleOnGestureListener {
  private static final int SWIPE_MIN_DISTANCE = 75;
  private static final int SWIPE_MAX_OFF_PATH = 250;
  private static final int SWIPE_THRESHOLD_VELOCITY = 200;

  @Override
  public boolean onFling(MotionEvent e1, MotionEvent e2, 
      float velocityX, float velocityY) {
    try {
      if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH)
        return false;
      // right to left swipe
      if (e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE
          && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
        moveNextOrPrevious(1);
      } else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE
          && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
        moveNextOrPrevious(-1);
      }
    } catch (Exception e) {
      // nothing
    }
    return false;
  }
}

moveNextOrPrevious() swaps in the previous or next image with the appropriate animation:

private void moveNextOrPrevious(int delta) {
  int nextImagePos = mCurrentPosition + delta;
  if (nextImagePos < 0) {
    mOverscrollLeft.setVisibility(View.VISIBLE);
    mOverscrollLeft.startAnimation(mOverscrollLeftFadeOut);
    return;
  }
  if (nextImagePos >= mImages.length) {
    mOverscrollRight.setVisibility(View.VISIBLE);
    mOverscrollRight.startAnimation(mOverscrollRightFadeOut);
    return;
  }

  mImageSwitcher.setInAnimation(
    delta > 0 ? mSlideInRight : mSlideInLeft);
  mImageSwitcher.setOutAnimation(
    delta > 0 ? mSlideOutLeft : mSlideOutRight);

  mCurrentPosition = nextImagePos;
  mImageSwitcher.setImageResource(mImages[mCurrentPosition]);
}

Notice how I show an overscroll grow when the user reaches the start or the end of the list of images. I make it visible immediately, and then use an animation to fade it away.

Right now all the logic is in MainActivity. I thought about encapsulating the viewer code into a custom view and bundling it into a jar file, but I am not sure how many people will find it useful, so laziness got the better of me. If you want to get a jar file to reuse this code, please let me know.

Until then, here is the source code: http://github.com/chiuki/android-swipe-image-viewer.

19 comments:

Inline coding questions will not be answsered. Instead, ask on StackOverflow and put the link in the comment.

  1. Great stuff!
    Hi, Ive been trying to implement the swiping gesture on an ePub. But i work with an iPad... So I want to tap on an image, it gets larger, and then swipe to go to the next image...
    Will this code work on the iPad??? !!!
    Thank you for your time!

    ReplyDelete
  2. The code is written in Java for Android, and will not work on the iPad.

    ReplyDelete
  3. Hi,

    Can you tell me if this will work on Android v3.x?

    thanks,

    Mirko

    ReplyDelete
    Replies
    1. Yes, it should work with Android v3.x since it uses the support library. Make sure you use the ViewPager solution outlined here: http://blog.sqisland.com/2012/09/android-swipe-image-viewer-with-viewpager.html

      Delete
  4. in my application take grid view with some images, if click on any image then it will be displayed a full screen image.after swipe those full screen image. Is this code is suitable for my requirement? if suitable where we placed this code?

    ReplyDelete
    Replies
    1. Yes, but please use the solution from http://blog.sqisland.com/2012/09/android-swipe-image-viewer-with-viewpager.html

      In particular, use the ViewPager in the activity for displaying the full screen image, and start that activity from onItemClick of your grid view.

      Delete
    2. can u provide any example for this requirement. it is very irritating me. can u provide example for swipe action in gridview images.

      Delete
  5. I want to swipe few Images from Left to Right & Vice-Versa also along with self timer just like we see on the websites.
    Help me out in achieving a task.

    Thank You.

    ReplyDelete
  6. i.e images should swipe automatically & also on user touch..

    ReplyDelete
    Replies
    1. You can set a timer to advance the image with ViewPager.setCurrentItem()

      Delete
  7. Hello, excellent gallery, where I can get one like this:

    http://www.entheosweb.com/tutorials/css/collage_gallery.asp

    ReplyDelete
  8. super! I guess this is the first image viewer for android! Any plans to add in async http for image downloading?

    ReplyDelete
  9. can this works in android 2.2..n how to add support library in project....i can't find viewpager in android 2.2!!!! any solution?

    ReplyDelete
    Replies
    1. Please use the ViewPager solution:
      http://blog.sqisland.com/2012/09/android-swipe-image-viewer-with-viewpager.html

      When you create a new Android project in Eclipse the support library is automatically included at libs/android-support-v4.jar. If you are not using Eclipse, you can go to your Android SDK directory and copy it out of extras/android/support/v4/android-support-v4.jar

      After that, import android.support.v4.view.ViewPager to use the ViewPager.

      Delete
  10. http://lalitkhandal.blogspot.in/2013/09/android-how-to-swipe-images-using-image.html

    check it...usefully

    ReplyDelete
  11. Thanks you so much... It helped me a lot...
    God Bless You...

    ReplyDelete