How to scale up Recycler View center item while scrolling in android?

后端 未结 4 1667
臣服心动
臣服心动 2020-12-16 05:41

I need to always highlight the center item in the recycler view while scrolling by scaling up.

相关标签:
4条回答
  • 2020-12-16 05:42

    As an addendum to Mayank Garg's answer and the comments it has saying that it does not work for the first or last items, this happens when you are using this class and also adding extra padding to the list at the beginning and end in order for the first item to appear already centered. In these situations, functions like getDecoratedRight() and getDecoratedLeft() will include the extra padding in the sizes they return. This messes up the calculation of the view's midpoint, and hence it won't work for the first and last items.

    A solution to this is to detect if the layout manager is displaying the beginning of the list or not, and use a conditional to use a different calculation which uses one of the decorated anchors as origin but then uses the view's halved width in order to find the midpoint.

    In other words, in Mayank's code you have:

    childMidpoint =
       (getDecoratedRight(child) + getDecoratedLeft(child)) / 2.f;
    

    You can replace this with something similar to the following:

    if (findFirstVisibleItemPosition() == 0 && i == 0) {
       childMidPoint = getDecoratedRight(child) - child.getWidth() / 2.f;
    } else {
       childMidPoint = getDecoratedLeft(child) + child.getWidth() / 2.f;
    }
    

    In other words, this checks that the first child view is, or isn't, the first item in the adapter, and if so uses either the left or right decorated horizontal position to calculate the midpoint by subtracting or adding the item's halved width.

    Another simpler alternative is:

    childMidpoint = child.getX() + child.getWidth() / 2.0f
    

    But then again, you need to test if this fits other constraints you may have on your layout/views, since there is probably a reason Mayank used getDecoratedLeft() instead of getX().

    0 讨论(0)
  • 2020-12-16 05:45

    You should follow this code, this helped me to scale up the center item in recycler view.

    public class CenterZoomLayoutManager extends LinearLayoutManager {
    
        private final float mShrinkAmount = 0.15f;
        private final float mShrinkDistance = 0.9f;
    
        public CenterZoomLayoutManager(Context context) {
            super(context);
        }
    
        public CenterZoomLayoutManager(Context context, int orientation, boolean reverseLayout) {
            super(context, orientation, reverseLayout);
        }
    
        @Override
        public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
            int orientation = getOrientation();
            if (orientation == VERTICAL) {
                int scrolled = super.scrollVerticallyBy(dy, recycler, state);
                float midpoint = getHeight() / 2.f;
                float d0 = 0.f;
                float d1 = mShrinkDistance * midpoint;
                float s0 = 1.f;
                float s1 = 1.f - mShrinkAmount;
                for (int i = 0; i < getChildCount(); i++) {
                    View child = getChildAt(i);
                    float childMidpoint =
                            (getDecoratedBottom(child) + getDecoratedTop(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;
            } else {
                return 0;
            }
        }
    
        @Override
        public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) {
            int orientation = getOrientation();
            if (orientation == HORIZONTAL) {
                int scrolled = super.scrollHorizontallyBy(dx, recycler, state);
    
                float midpoint = getWidth() / 2.f;
                float d0 = 0.f;
                float d1 = mShrinkDistance * midpoint;
                float s0 = 1.f;
                float s1 = 1.f - mShrinkAmount;
                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;
            } else {
                return 0;
            }
    
        }
    }
    

    center horizontal view

    0 讨论(0)
  • 2020-12-16 05:49

    Well, following Anarchofascist and Mayank, just add this override at the biggining of Mayank code to make the effect work with the first element.

    @Override
    public void onLayoutCompleted(RecyclerView.State state) {
        super.onLayoutCompleted(state);
    
        //aqui ele executa o codigo no estado inicial, originalmente ele nao aplicava no inicio
        //este codigo é em horizontal. Para usar em vertical apagar e copiar o codigo
        int orientation = getOrientation();
        if (orientation == HORIZONTAL) {
    
            float midpoint = getWidth() / 2.f;
            float d0 = 0.f;
            float d1 = mShrinkDistance * midpoint;
            float s0 = 1.f;
            float s1 = 1.f - mShrinkAmount;
            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);
            }
    
        } else {
    
            float midpoint = getHeight() / 2.f;
            float d0 = 0.f;
            float d1 = mShrinkDistance * midpoint;
            float s0 = 1.f;
            float s1 = 1.f - mShrinkAmount;
            for (int i = 0; i < getChildCount(); i++) {
                View child = getChildAt(i);
                float childMidpoint =
                        (getDecoratedBottom(child) + getDecoratedTop(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);
            }
    
        }
    }
    
    0 讨论(0)
  • 2020-12-16 06:03

    I slimmed down that solution and added the initial resize during onLayoutComplete. I didn't need vertical scrolling, so I took that part out.

    class CenterZoomLinearLayoutManager(
        context: Context,
        private val mShrinkDistance: Float = 0.9f,
        val mShrinkAmount: Float = 0.15f
    ) : LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false) {
    
        override fun onLayoutCompleted(state: RecyclerView.State?) {
            super.onLayoutCompleted(state)
            scaleChildren()
        }
    
        override fun scrollHorizontallyBy(dx: Int, recycler: RecyclerView.Recycler?, state: RecyclerView.State?): Int {
            return if (orientation == HORIZONTAL) {
                super.scrollHorizontallyBy(dx, recycler, state).also { scaleChildren() }
            } else {
                0
            }
        }
    
        private fun scaleChildren() {
            val midpoint = width / 2f
            val d1 = mShrinkDistance * midpoint
            for (i in 0 until childCount) {
                val child = getChildAt(i) as View
                val d = Math.min(d1, Math.abs(midpoint - (getDecoratedRight(child) + getDecoratedLeft(child)) / 2f))
                val scale = 1f - mShrinkAmount * d / d1
                child.scaleX = scale
                child.scaleY = scale
            }
        }
    }
    

    See https://github.com/pcholt/toy-card-carousel

    0 讨论(0)
提交回复
热议问题