Android RecyclerView 渐变背景

ild*_*niz 2 xml android gradient android-layout android-recyclerview

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

<shape>
    <gradient
        android:startColor="@color/colorPrimary500"
        android:endColor="@color/colorSecondary50"
        android:angle="90"/>
</shape>
Run Code Online (Sandbox Code Playgroud)

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

我认为的一种解决方案是将 recyclerview 的高度设置为其子级的总高度,但我不知道如何完成。

Mos*_*zar 6

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

  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)

}
Run Code Online (Sandbox Code Playgroud)

然后将其添加到RecyclerView.

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

    addItemDecoration(GradientItemDecoration(context))
}
Run Code Online (Sandbox Code Playgroud)

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

DividerItemDecoration如果您想仍然支持分隔线,您也可以从中进行扩展。


编辑

我创建了一个Github 存储库,展示了该解决方案的实际应用。