有没有一种方法可以使RecyclerView requireFadingEdge不受paddingTop和paddingBottom的影响

Che*_*eng 12 android android-recyclerview

目前,我需要使用paddingToppaddingBottomRecyclerView,因为我想避免复杂的空间计算,在我的第一RecyclerView项和最后一项。

但是,我注意到requiresFadingEdge效果也会受到影响。

这是我的XML

<androidx.recyclerview.widget.RecyclerView
    android:requiresFadingEdge="vertical"
    android:paddingTop="0dp"
    android:paddingBottom="0dp"

    android:overScrollMode="always"
    android:background="?attr/recyclerViewBackground"
    android:id="@+id/recycler_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:clipToPadding="false" />
Run Code Online (Sandbox Code Playgroud)

当paddingTop和paddingBottom为40dp时

在此处输入图片说明

如您所见,淡入淡出效果下降了40dp,这不是我想要的。


当paddingTop和paddingBottom为0dp时

在此处输入图片说明

褪色效果看起来不错。但是,我需要有非零paddingToppaddingBottom,为我RecyclerView


有没有一种方法,使RecyclerViewrequiresFadingEdge通过影响paddingToppaddingBottom

Moi*_*han 13

我为此找到了最好的官方解决方案。覆盖的这3种方法RecyclerView。其中最重要的作用是逐渐褪色。

首先创建您的recyclerView。

public class MyRecyclerView extends RecyclerView {

    // ... required constructor

    @Override
    protected boolean isPaddingOffsetRequired() {
        return true;
    }

    @Override
    protected int getTopPaddingOffset() {
        return -getPaddingTop();
    }

    @Override
    protected int getBottomPaddingOffset() {
        return getPaddingBottom();
    }
}
Run Code Online (Sandbox Code Playgroud)

而已。使用此回收视图,您将看到褪色边缘不受影响。

以下内容仅用于说明。如果您想在幕后知道。

为了了解这种边缘效果是如何工作的,我深入研究了使用该类的类android:requiresFadingEdge,然后发现它不是由处理,RecyclerView而是由View所有视图的父类处理。

在类的onDraw方法中,View我找到了利用该方法绘制淡入淡出边缘的代码isPaddingOffsetRequired。仅用于处理淡入淡出效果。

根据文档,如果要更改衰落边缘的行为,则该方法应由子类覆盖。默认情况下返回false。因此,通过返回,true我们要求视图在绘制视图时对边缘应用一些偏移。

查看以下类的onDraw方法片段View以了解计算。

final boolean offsetRequired = isPaddingOffsetRequired();
if (offsetRequired) {
    paddingLeft += getLeftPaddingOffset();
}

int left = mScrollX + paddingLeft;
int right = left + mRight - mLeft - mPaddingRight - paddingLeft;
int top = mScrollY + getFadeTop(offsetRequired);
int bottom = top + getFadeHeight(offsetRequired);

if (offsetRequired) {
    right += getRightPaddingOffset();
    bottom += getBottomPaddingOffset();
}
Run Code Online (Sandbox Code Playgroud)

如我们所见,top变量是使用初始化的getFadeTop(offsetRequired)

protected int getFadeTop(boolean offsetRequired) {
    int top = mPaddingTop;
    if (offsetRequired) top += getTopPaddingOffset();
    return top;
}
Run Code Online (Sandbox Code Playgroud)

在此方法中,top通过在需要偏移量时将topOffSet的值相加来计算。因此,要反转效果,我们需要传递您要传递的填充的负值。所以我们需要返回-getPaddingTop()

现在,对于bottom,我们没有传递负值,因为bottom正在处理top + height。因此,传递负值会使从底部开始的淡入淡出更短,因此我们需要添加底部填充以使其正确可见。

您可以覆盖这4种方法来使用它。 getLeftPaddingOffset(), getRightPaddingOffset(), getTopPaddingOffset(), getBottomPaddingOffset()


Ali*_*yan 2

我提出一些解决方案,希望对您有所帮助

1-RecyclerView.ItemDecoration(保留requiresFadingEdge

class ItemDecoration(private val spacing: Int) : RecyclerView.ItemDecoration(){

   override fun getItemOffsets(outRect: Rect, view: View, parent: 
   RecyclerView, state: RecyclerView.State?) {

   val position = parent.getChildAdapterPosition(view)
   when(position)
    0 ->                          { outRect.top    = spacing /*40dp*/ }
    parent.adapter.itemCount-1 -> { outRect.bottom = spacing /*40dp*/ }

}
Run Code Online (Sandbox Code Playgroud)

2-多个ViewHolder(取决于ViewHolder是保留还是删除requiresFadingEdge/sf/answers/1837182441/

3-渐变(删除requiresFadingEdge

使用可绘制对象制作两个渐变,如下所示:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
    android:type="linear"
    android:angle="90"
    android:startColor="#000"
    android:endColor="#FFF" />
</shape>
Run Code Online (Sandbox Code Playgroud)

并设置background为Recyclerview的顶部和底部两个视图。