使用android提供的GridLayoutManager、LinearLayoutManagerd,在xml添加fadingEdgeLength和requiresFadingEdge是有渐变效果的。
ini
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv"
android:layout_width="0dp"
android:layout_height="0dp"
android:fadingEdgeLength="50dp"
android:requiresFadingEdge="horizontal"/>

但是用了自定义LayoutManager之后就失效了。
原因
自定义的LayoutManager没有重写computeHorizontalScrollOffset、computeHorizontalScrollRang等方法。
less
public int computeHorizontalScrollExtent(@NonNull State state) {
return 0;
}
public int computeHorizontalScrollOffset(@NonNull State state) {
return 0;
}
public int computeHorizontalScrollRange(@NonNull State state) {
return 0;
}
public int computeVerticalScrollExtent(@NonNull State state) {
return 0;
}
public int computeVerticalScrollOffset(@NonNull State state) {
return 0;
}
public int computeVerticalScrollRange(@NonNull State state) {
return 0;
}
渐变效果是在View.draw()中实现的。draw渐变效果时,是分了上下左右,四个方向来绘制的。只要了解了一个方向的渐变效果就一通百通了。
在View绘制渐变效果时,getTopFadingEdgeStrength返回的是0,导致drawTop为false,所以没有渐变效果。
ini
public void draw(@NonNull Canvas canvas) {
final int viewFlags = mViewFlags;
// 是否设置了requiresFadingEdge
boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0;
boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0;
boolean drawTop = false;
float topFadeStrength = 0.0f;
if (verticalEdges) {
// 顶部渐变的强度,范围是0~1
// 最终会调用到LayoutManger.computeVerticalScollOffset,
// 因为自定义的LayoutManger没有重写该方法,所以返回的是0.
topFadeStrength = Math.max(0.0f, Math.min(1.0f, getTopFadingEdgeStrength()));
// fadeHeight就是在xml中设置的fadingEdgeLength
// 因为topFadeStrength为0,所以drawTop就为false了
drawTop = topFadeStrength * fadeHeight > 1.0f;
}
saveCount = canvas.getSaveCount();
int topSaveCount = -1;
int solidColor = getSolidColor();
if (solidColor == 0) {
if (drawTop) {
topSaveCount = canvas.saveUnclippedLayer(left, top, right, top + length);
}
} else {
scrollabilityCache.setFadeColor(solidColor);
}
// 绘制渐变效果
if (drawTop) {
matrix.setScale(1, fadeHeight * topFadeStrength);
matrix.postTranslate(left, top);
fade.setLocalMatrix(matrix);
p.setShader(fade);
if (solidColor == 0) {
// 和背景颜色一致的渐变效果
canvas.restoreUnclippedLayer(topSaveCount, p);
} else {
// getSolidColor获取到的颜色渐变
canvas.drawRect(left, top, right, top + length, p);
}
}
}
解决
方法一:重写LayoutManger的相关方法,返回对应的值。
方法二:直接重写RecylerView的getBottomFadingEdgeStrength、getLeftFadingEdgeStrength等方法。
csharp
protected float getBottomFadingEdgeStrength() {
return 1f;
}
protected float getLeftFadingEdgeStrength() {
return 1f;
}
protected float getRightFadingEdgeStrength() {
return 1f;
}
protected float getTopFadingEdgeStrength() {
return 1f;
}