【问题标题】:Recycler view - resizing item view while scrolling (for carousel like effect)回收站视图 - 滚动时调整项目视图的大小(用于类似轮播的效果)
【发布时间】:2017-05-09 12:30:56
【问题描述】:

我需要创建一个垂直的recyclerview,其中屏幕中心的项目视图应该调整大小以在滚动时具有类似缩放的效果。

我尝试过但没有用的方法:

  1. 添加一个滚动监听器并按位置循环遍历项目视图,测量居中位置,然后更新居中 viewLayoutParams

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

    • 仅在滚动已经/将要完成后更新视图,而不是在正在执行滚动项目期间。
  3. 剩下的最后一个选项是实现自己的自定义LayoutManager,它将扩展默认LayoutManager

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

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

【问题讨论】:

标签: java android performance android-layout android-recyclerview


【解决方案1】:

我找到了this answer on SO,它在水平方向上做了完全相同的事情。 Answer 提供了一个扩展LinearLayoutManager 的有效解决方案。我对它进行了一些修改以适应垂直列表并且它可以工作。如果执行中有任何错误,请在 cmets 中告诉我。干杯!

自定义布局管理器:

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

    }
}

水平方向:

垂直方向:

【讨论】:

  • 你知道吗,如何让它循环?我有 10 个项目的水平回收视图。我想无限滚动它。即位置 1 将在完成所有项目后再次出现。
  • @RonakThakkar 我认为这样的技巧会起作用:stackoverflow.com/a/45114415/3830694
  • @Krupal,你有没有想过如何包含下一个可滚动项目的窥视?
  • @KrupalShah,感谢您提供此解决方案,但这似乎不适用于不同的移动屏幕尺寸。我已经用不同的屏幕尺寸对此进行了测试,在某些设备中左右项目看起来很完美,而在某些设备中则不然。我在这里谈论水平列表。
  • @MohammedFarhan 这似乎对我有用。不过你可以自己修改。
猜你喜欢
  • 1970-01-01
  • 2016-08-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-11
  • 1970-01-01
  • 1970-01-01
  • 2016-09-22
相关资源
最近更新 更多