循环视图中每个项目的视差效果?

9
我正在尝试使用视差效果并遇到一些奇怪的错误,想知道是否有人可以提供一些帮助。我看过的唯一一个有效实现视差效果的应用是Soundcloud。它非常微妙,但每个项目都有一个图像背景,并且在滚动时具有视差效果。
我已经创建了一个自定义的RecyclerView来处理这个问题,以下是我的进展:
public class ParallaxScrollListener extends RecyclerView.OnScrollListener {

private float scrollSpeed = 0.5f;

@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
    super.onScrolled(recyclerView, dx, dy);
    LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();

    int firstVisible = layoutManager.findFirstVisibleItemPosition();
    int visibleCount = Math.abs(firstVisible - layoutManager.findLastVisibleItemPosition());

    Matrix imageMatrix;
    float tempSpeed = -100;

    if (dy > 0) {
        tempSpeed = scrollSpeed;
    } else if (dy < 0) {
        tempSpeed = -scrollSpeed;
    }

    for (int i = firstVisible; i < (firstVisible + visibleCount); i++) {
        ImageView imageView = ((MyClass.MyAdapter.MyViewHolder) recyclerView.getLayoutManager().findViewByPosition(i).getTag()).image;
        if (imageView != null) {
            imageMatrix = imageView.getImageMatrix();
            imageMatrix.postTranslate(0, tempSpeed);
            imageView.setImageMatrix(imageMatrix);
            imageView.invalidate();
        }
    }
}

在我的RecyclerView适配器的onBindView方法中,我也有以下内容:
 Matrix matrix = viewHolder.image.getImageMatrix();
 matrix.postTranslate(0, 0);
 viewHolder.image.setImageMatrix(matrix);
 viewHolder.itemView.setTag(viewHolder);

最后,在onViewRecycled方法内,我有以下内容:

@Override
    public void onViewRecycled(MyViewHolder viewHolder) {
        super.onViewRecycled(viewHolder);
        if (viewHolder.image != null) {
            viewHolder.image.setScaleType(ImageView.ScaleType.MATRIX);
            Matrix matrix = viewHolder.image.getImageMatrix();
            // this is set manually to show to the center
            matrix.reset();
            viewHolder.image.setImageMatrix(matrix);
        }
}

我一直在GitHub上使用这个代码来了解其思想

视差效果可实现,但是我的RecyclerView中的视图也会移动。我有一个在图片下方的CardView,它会移动,导致每个项之间出现大的间隙。滚动是造成这种情况的原因,滚动得越多,间隙就越大,并且随着视差将图像移出其边界,图像变得越来越小。

我尝试过调整OnScrollListener中的scrollSpeed等数字,虽然它减少了bug,但也减少了视差效果。

是否有人有任何想法,可以让我在RecyclerView中的每个项目上实现没有bug的视差效果?我觉得我在这方面已经取得了一些进展,但仍然存在很多问题,而我不知道下一步该怎么做。

P.s我已经尝试过查看第三方库,但它们似乎只使用类似于CoordinatorLayout的标题栏视差效果,我没找到能够在列表中每个项上实现视差效果的库。

即使我无法解决问题,我希望这个问题能引发一场好的讨论,因为在Android中,视差效果似乎并没有得到充分利用,关于它的资料也非常少。

谢谢您的时间,感谢任何帮助。


应该被视差化的图像在每个视图上都相同吗?还是您想/需要能够在onBindVH中为每个项目设置它? - David Medenjak
不同的图像,所以每次都需要设置。我找到了一个库来完成它,很快会发布我的答案。 - RED_
2个回答

4
我使用这个库成功实现了视差效果:https://github.com/yayaa/ParallaxRecyclerView。如果你也在尝试这个功能,不妨玩一下这个库,看看它是如何实现的。这个库的实现原理与我的代码类似,但实际运行起来更加稳定!哈哈。

2
你走在正确的道路上。你需要使用一个ScrollListener。此外,你需要访问RecyclerView的LayoutManager并迭代遍历所有可见的项目,并根据滚动的像素数量设置translateY
事情变得有点复杂,因为你不能使用recyclerView.getChildAt(pos),因为LayoutManager负责布局元素,它们在LayoutManager中可能与getChildAt(pos)中的顺序不同。
因此,算法基本上应该像这样(伪代码,假设使用LinearLayoutManager):
for (int i = layoutManager.findFirstVisibleItemPosition(); i <= layoutmanager.findLastVisibleItemPosition; i++){

   // i is the adapter position

   ViewHolder vh = recyclerView.findViewHolderForAdapterPosition(i);
   vh.imageView.setTranslationY( computedParalaxOffset ); // assuming ViewHolder has a imageView field on which you want to apply the parallax effect
}

谢谢回复。但这不是我已经拥有的吗?在我的滚动监听器中,我正在使用LinearLayoutManager来计算视图。使用setTranslationY似乎也没有任何作用。postTranslate创建了视差效果并且有效,但我仍然有问题,就像我在问题中所概述的那样。 - RED_
你说得对,我忽略了那个。我的错。所以,你的问题基本上是如何计算 computedParalaxOffset 的值,对吗? - sockeqwe
最终我找到了一个库,可以解决所有问题。看起来他们需要一个自定义的ImageView,而我没有使用它,这可能是我的问题的一部分。 - RED_

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接