Android 具有渐变背景的RecyclerView

Android RecyclerView with gradient background

是否可以将recyclerview的背景设置为渐变,让渐变覆盖整个recyclerview而不是横跨屏幕?换句话说,我希望背景可绘制高度等于所有项目的总高度,以便当用户向下滚动时背景颜色发生变化,并且只有当用户向下滚动到最后一个时才能达到渐变的结束颜色项目。

<shape>
    <gradient
        android:startColor="@color/colorPrimary500"
        android:endColor="@color/colorSecondary50"
        android:angle="90"/>
</shape>

当我使用此形状作为带有 height="wrap_content" 的 recyclerview 的背景时,我可以向下滚动,但渐变跨越屏幕高度并且是静态的,结束颜色(黄色)始终位于底部屏幕和开始颜色(蓝色)总是在顶部: screenshot

我想到的一个解决方案是将 recyclerview 的高度设置为它的子项的总高度,但我不知道该怎么做。

有几种方法可以实现这一点并使背景可滚动。

  1. 将背景移动到与RecyclerView总高度相同的新视图,并根据RecyclerView当前y滚动位置滚动。

这种方法有很多缺点,随着您的应用程序和代码库的增长,维护起来也不容易

  1. 我们可以使用自定义 RecyclerView.ItemDecoration 来管理该背景并使用 RecyclerView 无缝滚动它。
import android.content.Context
import android.graphics.Canvas
import android.graphics.Rect
import android.graphics.drawable.Drawable
import android.view.View
import androidx.recyclerview.widget.RecyclerView

class GradientItemDecoration(context: Context) : RecyclerView.ItemDecoration() {

    private var backgroundDrawable: Drawable? = null

    init {
        backgroundDrawable = context.getDrawable(R.drawable.background_gradient)
    }

    override fun onDraw(canvas: Canvas, parent: RecyclerView, state: RecyclerView.State) {
        if (parent.layoutManager == null || backgroundDrawable == null) {
            return
        }

        val left = parent.paddingLeft
        val top = -parent.computeVerticalScrollOffset()
        val right = parent.width - parent.paddingRight

        val bottom = parent.computeVerticalScrollRange() + top
        backgroundDrawable?.setBounds(left, top, right, bottom)
        backgroundDrawable?.draw(canvas)
    }

    override fun getItemOffsets(
        outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State
    ) = outRect.set(0, 0, 0, 0)

}

然后添加到RecyclerView

recyclerView = findViewById<RecyclerView>(R.id.recycler_view).apply {
    ....

    addItemDecoration(GradientItemDecoration(context))
}

在上面的代码中,我们在 GradientItemDecoration 中加载了渐变图像,并在用户与 RecyclerView 交互时在 onDraw 中更新了它的边界。

如果您仍想支持分隔符,也可以从 DividerItemDecoration 扩展。


编辑

我创建了一个 Github repo 来展示这个解决方案的实际应用。