GridView Transition for Image Gallery

Today, I make an example to show how to create transition for GridView image gallery on Android. In the example, I create custom bitmap scale when gridview item clicked by user. Let’s take a look at the following demo of GridView transition:

Main flow of this example:

  • When GridView’s item clicked by user, we will capture the details of imageview (top, left, width, height, title, url ….. of the image to display). All those informations are sent to DetailsActivity by extra intent.
  • DetailsActivity lauched and the thumbnail will be zoomed.

Create GridView

Declare GridView in layout file, declare GridView item layout, declare Adapter class…
You can get all in my source code.

Capture and send the thumbnails details to DetailsActivity

When gridview’s item clicked by user, the event handled by method mGridView.setOnItemClickListener. In this, you can get thumbnail details and send to DetailsActivity via Intent bundle.

mGridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {  
  public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
    Item item = (Item) parent.getItemAtPosition(position);
    Intent intent = new Intent(MainActivity.this, DetailsActivity.class);
    ImageView imageView = (ImageView) v.findViewById(R.id.activity_details_iv_image);
    int[] screenLocation = new int[2];
    imageView.getLocationOnScreen(screenLocation);
    intent.putExtra("left", screenLocation[0])
      .putExtra("top", screenLocation[1])
      .putExtra("width", imageView.getWidth())
      .putExtra("height", imageView.getHeight())
      .putExtra("title", item.getTitle())
      .putExtra("image", item.getImage());
    startActivity(intent);
  }
});

Read bundble data passed from Intent

In DetailsActivity, get thumnail details sent form MainActivity via bundble data.

Bundle bundle = getIntent().getExtras();  
mTopThumbnail = bundle.getInt("top");  
mLeftThumbnail = bundle.getInt("left");  
mWidthThumbnail = bundle.getInt("width");  
mHeightThumbnail = bundle.getInt("height");  
String title = bundle.getString("title");  
String image = bundle.getString("image");  

Implement addOnPreDrawListener callback

In DetailsActivity, implement ViewTreeObserver.OnPreDrawListener:

ViewTreeObserver observer = mIvImage.getViewTreeObserver();  
observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {  
  @Override public boolean onPreDraw() {
    mIvImage.getViewTreeObserver().removeOnPreDrawListener(this);
    int[] screenLocation = new int[2];
    mIvImage.getLocationOnScreen(screenLocation);
    mLeft = mLeftThumbnail - screenLocation[0];
    mTop = mTopThumbnail - screenLocation[1];
    mWidthScale = (float) mWidthThumbnail / mIvImage.getWidth();
    mHeightScale = (float) mHeightThumbnail / mIvImage.getHeight();
    enterAnimation();
    return true;
  }
});

Create enter and exit animation

private void enterAnimation() {  
  mIvImage.setPivotX(0);
  mIvImage.setPivotY(0);
  mIvImage.setScaleX(mWidthScale); 
  mIvImage.setScaleY(mHeightScale);
  mIvImage.setTranslationX(mLeft);
  mIvImage.setTranslationY(mTop);
  TimeInterpolator sDecelerator = new DecelerateInterpolator();
  mIvImage.animate()
    .setDuration(DURATION)
    .scaleX(1)
    .scaleY(1)
    .translationX(0)
    .translationY(0)
    .setInterpolator(sDecelerator);
  ObjectAnimator oAnimator = ObjectAnimator.ofInt(mColorDrawable, "alpha", 0, 255);
  oAnimator.setDuration(DURATION); oAnimator.start();
}
public void exitAnimation(final Runnable endAction) {  
  TimeInterpolator sInterpolator = new AccelerateInterpolator(); 
  mIvImage.animate()
    .setDuration(DURATION)
    .scaleX(mWidthScale)
    .scaleY(mHeightScale)
    .translationX(mLeft)
    .translationY(mTop)
    .setInterpolator(sInterpolator)
    .withEndAction(endAction);
  ObjectAnimator oAnimator = ObjectAnimator.ofInt(mColorDrawable, "alpha", 0);
  oAnimator.setDuration(DURATION);
  oAnimator.start();
}

@Override public void onBackPressed() {
  exitAnimation(new Runnable() {
    public void run() {
      finish();
    }
  });
}

You can download complete source code form here.