google / flexbox-layout

Flexbox for Android
Apache License 2.0
18.26k stars 1.8k forks source link

FlexboxLayoutManager stops before reaching the bottom when flicking fast #556

Open herbeth1u opened 4 years ago

herbeth1u commented 4 years ago

Issues and steps to reproduce

Hello. When flicking fast enough a FlexboxLayoutManager to reach the bottom, the scroll sometimes stops before reaching the bottom. See the video: device-2020-08-16-163621-edit We can see a first overscroll, just below the "My labels" label, yet there are still items to show below. When flicking a second time, it properly reaches the bottom.

This is an issue I have reproduced a few times in the past (not necessarily on this specific RecyclerView). Reproducing it depends on various factors (it essentially depends on how you flick). Basically, it is easier to reproduce on a FlexboxLayoutManager with a lot of items, in ROW mode. The flick should be fast but small.

It looks like in some cases, the FlexboxLayoutManager doesn't have time to inflate the views fast enough, so the scroll stops before the FlexboxLayoutManager manages to inflate the next views. My items are actually not very wide, nor very high, so multiple of them can fit on the same row (which means that the FlexboxLayoutManager has to inflate more of them to follow the scroll speed). This item size could be a relevant factor in reproducing the issue.

Expected behavior

When flicking through a FlexboxLayoutManager, it should never stop with an overscroll before reaching the very bottom. We should always be able to reach the bottom with a single flick (assuming that the flick is powerful enough of course).

Version of the flexbox library

2.0.1

Link to code

Not much relevant code to give; the RecyclerView from the GIF is initialized like so:

recyclerView.layoutManager = FlexboxLayoutManager(activity).apply {
    alignItems = AlignItems.CENTER
    justifyContent = JustifyContent.FLEX_START
}

FYI the RV is not inside a NestedScrollView or any other scrolling parent (so this is probably unrelated to #420 ).

Possible leads?

As a matter of fact, when debugging the issue, I stumbled upon this block of code, and found it could be a reason for the FlexboxLayoutManager not inflating the views fast enough:

FlexboxHelper.java
if (sumCrossSize > needsCalcAmount && reachedToIndex) {
    // Stop the calculation if the sum of cross size calculated reached to the point
    // beyond the needsCalcAmount value to avoid unneeded calculation in a
    // RecyclerView.
    // To be precise, the decoration length may be added to the sumCrossSize,
    // but we omit adding the decoration length because even without the decorator
    // length, it's guaranteed that calculation is done at least beyond the
    // needsCalcAmount
    break;
}

And indeed, after forking the project and commenting these lines, I was surprised to see I couldn't reproduce the issue!
I thought this was a happy coincidence that @phcannessondkt suggested in #420 (PR #554) to remove these lines as well, to fix an (apparently) unrelated issue.

Don't hesitate to ask for more info. Thanks!

herbeth1u commented 4 years ago

More info: removing the lines in FlexboxHelper.java works because all the items are inflated immediately, which defeats the whole purpose of the RecyclerView. This doesn't look like a solution.

Also, I enabled FlexboxLayoutManager's logs, and this is exactly what happens when I flick and the RecyclerView stops before the end:

D/FlexboxLayoutManager: computeVerticalScrollOffset: 0
E/D: [onBindViewHolder]
E/D: [onBindViewHolder]
D/FlexboxLayoutManager: computeVerticalScrollOffset: 258
D/FlexboxLayoutManager: computeVerticalScrollRange: 3864
D/FlexboxLayoutManager: computeVerticalScrollExtent: 1414
D/FlexboxLayoutManager: computeVerticalScrollOffset: 258
D/FlexboxLayoutManager: computeVerticalScrollRange: 3864
D/FlexboxLayoutManager: computeVerticalScrollExtent: 1414

The scroll offset goes directly from 0 to 258 (i.e. the offset just under "My labels"), because I flicked fast. But since there are no intermediary scroll offset values, could it cause FlexboxLayoutManager to not detect it has to inflate new views?

bluelabeldeveloper1 commented 3 years ago

I have a similar issue when I scroll horizontally. Only facing an issue when I put the recycler view in the item with a nested scroll view.

item.xml <RelativeLayout android:id="@+id/relContainer" android:layout_width="@dimen/_93sdp" android:layout_height="wrap_content" android:orientation="vertical">

    <androidx.cardview.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="@dimen/_2sdp"
        app:cardBackgroundColor="@color/color_white"
        app:cardCornerRadius="@dimen/_2sdp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <LinearLayout
                android:id="@+id/linTopContainer"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:background="@color/color_196ed9"
                android:baselineAligned="false"
                android:orientation="horizontal"
                android:padding="@dimen/_5sdp">

                <LinearLayout
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_weight="1"
                    android:orientation="vertical">

                    <com.google.android.material.textview.MaterialTextView
                        android:id="@+id/txtOrderNumber"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:ellipsize="end"
                        android:fontFamily="@font/robotobold"
                        android:singleLine="true"
                        android:textColor="@color/color_white"
                        android:textSize="@dimen/_4ssp"
                        tools:text="#123" />

                    <com.google.android.material.textview.MaterialTextView
                        android:id="@+id/txtItemDetailStationName"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:fontFamily="@font/robotoregular"
                        android:textColor="@color/color_white"
                        android:textSize="@dimen/_4ssp"
                        tools:text="Curbside - Danny D." />

                </LinearLayout>

                <RelativeLayout
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content">

                    <Chronometer
                        android:id="@+id/chrnOrderTiming"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:fontFamily="@font/robotoregular"
                        android:textColor="@color/color_white"
                        android:textSize="@dimen/_5ssp" />

                    <com.google.android.material.imageview.ShapeableImageView
                        android:id="@+id/imgOrderTick"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_marginTop="@dimen/_3sdp"
                        android:src="@drawable/ic_tick_icon"
                        android:visibility="gone" />

                </RelativeLayout>

            </LinearLayout>

            <androidx.core.widget.NestedScrollView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_below="@id/linTopContainer"
                android:background="@color/color_white"
                android:fillViewport="true"
                android:scrollbars="none">

                <androidx.recyclerview.widget.RecyclerView
                    android:id="@+id/rvOrderListStationOrderItems"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
                    tools:itemCount="5"
                    tools:listitem="@layout/item_station_order_item" />

            </androidx.core.widget.NestedScrollView>

        </RelativeLayout>

    </androidx.cardview.widget.CardView>

Video Link

LeoXJ978 commented 2 years ago

My problem is that scrolling is very sluggish and jittery (with roughly 4x20 = 80 views on the screen), and often with abrupt stops. I thought removing the lines of code as suggested may help with my situation, but no. Without those lines, the problem is worse, much slower and with blank rows on the screen.