Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to make RecyclerView requiresFadingEdge unaffected by paddingTop and paddingBottom

Currently, I need to use paddingTop and paddingBottom of RecyclerView, as I want to avoid complex space calculation, in my first RecyclerView item and last item.

However, I notice that, requiresFadingEdge effect will be affected as well.

This is my 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" />

When paddingTop and paddingBottom is 40dp

enter image description here

As you can see, the fading effect shift down by 40dp, which is not what I want.


When paddingTop and paddingBottom is 0dp

enter image description here

Fading effect looks fine. But, I need to have non-zero paddingTop and paddingBottom, for my RecyclerView.


Is there a way to make RecyclerView's requiresFadingEdge unaffected by paddingTop and paddingBottom?

like image 484
Cheok Yan Cheng Avatar asked Mar 27 '19 08:03

Cheok Yan Cheng


Video Answer


2 Answers

I found the best and kind of official solution for this. Override this 3 methods of RecyclerView. Which play most important role for fading edge.

First create your 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();
    }
}

That's it. Use this recyclerview and you will see fadding edge unaffected.

Following content is just for explanation. If you want to know behind the scene.

To understand how this edge effect is working I dig into the class where android:requiresFadingEdge is used, And I found that it's not handled by RecyclerView instead It's handled by View class which is parent for all view.

In onDraw method of View class I found the code for drawing fade edge by using help of this method isPaddingOffsetRequired. Which used only for handling the fade effect.

According to documentation this method should be overridden by child class If you want to change the behaviour of fading edge. Bydefault It return false. So By returning true we are asking view to apply some offset for edge at the time of view drawing.

Look following snippet of onDraw method of View class to understand the calculation.

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();
}

As we can see top variable is initialize using getFadeTop(offsetRequired).

protected int getFadeTop(boolean offsetRequired) {
    int top = mPaddingTop;
    if (offsetRequired) top += getTopPaddingOffset();
    return top;
}

In this method, top is calculated by adding value of topOffSet when offset is needed. So to reverse the effect we need to pass negative value of padding which you are passing. so we need to return -getPaddingTop().

Now for bottom we are not passing negative value because bottom is working on top + height. So passing negative value make fade more shorter from the bottom so we need to add bottom padding to make it proper visible.

You can override this 4 method to play with it. getLeftPaddingOffset(), getRightPaddingOffset(), getTopPaddingOffset(), getBottomPaddingOffset()

like image 162
Moinkhan Avatar answered Sep 27 '22 17:09

Moinkhan


There are many ways to achieve that but I preferred below solution that works for me. You can use a third-party library called Android-FadingEdgeLayout checkout here

Here is a dependency.

implementation 'com.github.bosphere.android-fadingedgelayout:fadingedgelayout:1.0.0'

In yours.xml

<com.bosphere.fadingedgelayout.FadingEdgeLayout
    android:id="@+id/fading_edge_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:fel_edge="top|left|bottom|right"
    app:fel_size_top="40dp"
    app:fel_size_bottom="40dp"
    app:fel_size_left="0dp"
    app:fel_size_right="0dp">

    <androidx.recyclerview.widget.RecyclerView   
        android:paddingTop="0dp"
        android:paddingBottom="0dp"
        android:overScrollMode="always"
        android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:clipToPadding="false" />

</com.bosphere.fadingedgelayout.FadingEdgeLayout>

Change your ReacyclerView property according to your need. below is example image with all sided sades. I hope that will help you.

enter image description here

Credits Android-FadingEdgeLayout

like image 29
Mehul Solanki Avatar answered Sep 27 '22 17:09

Mehul Solanki