Recycler视图 - 滚动时调整项目视图的大小(对于旋转木马效果)

Kru*_*hah 24 java performance android android-layout android-recyclerview

我需要创建一个垂直的Recyclerview,其中应调整屏幕中心的项目视图,以便在滚动时具有缩放效果.

我尝试但没有奏效的事情:

  1. 添加滚动侦听器并按位置循环浏览项目视图,测量居中位置,然后更新LayoutParams居中view.

    • RecyclerView在滚动时不会计算项目的位置或更新视图.IllegalStateException如果执行此类操作,则抛出onScrolled
  2. LayoutParamsonScrollStateChanged滚动状态下更改居中的项目视图是IDLESETTLING.

    • 仅在滚动已经/将要完成之后才更新视图,而不是在滚动项目期间执行.
  3. 最后的选择仍然是实现自己的自定义LayoutManager,将扩展默认LayoutManager.

    • 据我所知,实现自定义Layoutmanager涉及处理需要处理的更复杂的计算.

任何其他解决方案或想法将不胜感激.

Kru*_*hah 65

在SO上找到了这个答案,它在横向上做了完全相同的事情.答案提供了扩展的工作解决方案LinearLayoutManager.我修改了一下以适应垂直列表并且它可以工作.如果实施中有任何错误,请在评论中告诉我.干杯!

自定义布局管理器

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;
        }

    }
}
Run Code Online (Sandbox Code Playgroud)

水平方向: 在此输入图像描述

垂直方向:

在此输入图像描述