Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Zoom central image recycler view

I have RecyclerView with images. It based on this solution. Images are lazy loaded into view with Glide. I need to add zoom on central image like in this: example

How can i do it?

like image 823
Andrey Rankov Avatar asked Feb 10 '16 08:02

Andrey Rankov


1 Answers

The most direct way to affect what you want is to extend LinearLayoutManager. As you've no doubt discovered, hooking into the scroll events properly is a pain:

So let's extend the manager. We'll create a few parameters that you might expose.

 public class ZoomCenterCardLayoutManager extends LinearLayoutManager {
   // Shrink the cards around the center up to 50%
   private final float mShrinkAmount = 0.5f;
   // The cards will be at 50% when they are 75% of the way between the
   // center and the edge.
   private final float mShrinkDistance = 0.75f;

Fill out your constructors, and then override scrollHorizontallyBy:

   @Override 
   public int scrollHorizontallyBy(int dx, 
      RecyclerView.Recycler recycler, RecyclerView.State state) {

Call the parent's version and save the distance travelled. We'll need to return this at the end of the method:

      int scrolled = super.scrollHorizontallyBy(dx, recycler, state);

We are going to set up a simple linear interpolation. It looks nice enough.

      float midpoint = getWidth() / 2.f;
      float d0 = 0.f;
      float d1 = mShrinkDistance * midpoint;
      float s0 = 1.f;
      float s1 = 1.f - mShrinkAmount;

Loop through all of the active children of the control, run the interpolation, and set the scale of the child.

      for (int i = 0; i < getChildCount(); i++) {
        View child = getChildAt(i);
        float childMidpoint = 
           (getDecoratedRight(child) + getDecoratedLeft(child)) / 2.f;
        float d = Math.min(d1, Math.abs(midpoint - childMidpoint));
        float scale = s0 + (s1 - s0) * (d - d0) / (d1 - d0);
        child.setScaleX(scale);
        child.setScaleY(scale);
      }

      return scrolled;
   }

This is almost all you need. One final step is to make sure that this adjustment is called after initialization -- otherwise the zooming won't take effect until the first time the control is moved:

   @Override
   public void onLayoutChildren(Recycler recycler, State state) {
     super.onLayoutChildren(recycler, state);
     scrollHorizontallyBy(0, recycler, state);
   }

 }

And that's all there is to it. Super responsive, and you can drop this new layout manager into any horizontal recycler.

like image 117
Michael Hays Avatar answered Nov 18 '22 16:11

Michael Hays