Showing posts with label view. Show all posts
Showing posts with label view. Show all posts

Wednesday, September 19, 2012

Android: Swipe Image Viewer with ViewPager

A few months ago I complained that there is no standard widget for a swipe image viewer. I just asked about it on Twitter, and discovered that ViewPager is what I wanted.

I updated my github project with a ViewPager implementation, and it's so much simpler. On top of that, the images slide as your finger swipes across the screen, giving a much more satisfactory feedback.

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.

Monday, January 9, 2012

Android: Square View

In Monkey Write, the character sits in a square. Initially I just hard-coded the width to be equal to the height, but I wanted them to scale with the device dimensions. Today I found an elegant way to do it, with 3 lines of code in my custom View:

public void onMeasure(int widthSpec, int heightSpec) {
  super.onMeasure(widthSpec, heightSpec);
  int size = Math.min(getMeasuredWidth(), getMeasuredHeight());
  setMeasuredDimension(size, size);
}

Since my class extends View, I can reuse all the measurement logic by calling super. After that, I take the measured width and height, find the smaller one, and use it to set the width to be the same as the height.

I made a sample project to test the SquareView. It is set to take one third of the screen width, and the easiest way to try it with different dimensions is to rotate the screen.

Source code: http://github.com/chiuki/android-square-view.