Prevent RecyclerView from scrolling under AppBarLayout before AppBarLayout is collapsed

牧云@^-^@ 提交于 2019-11-30 05:19:54

问题


I'm creating a RecyclerView with header where the header collapses as you scroll up the RecyclerView. I can achieve this very closely with the layout below, with a transparent AppBarLayout, and MyCoolView which is the header. The parallax effect works great.

However, if the header is still visible and I fling the RecyclerView, the RV scrolls slowly to the top and some of the items are under the Toolbar until the RV reaches the top of the view. I've been playing around with the scrollFlags but haven't achieved a desirable result. Any suggestions on how to improve the fling experience so the items don't get clipped?

View the video and watch when its flinged --- https://www.dropbox.com/s/jppd6m7zo41k23z/20160609_151309.mp4?dl=0

<android.support.design.widget.CoordinatorLayout>

     <android.support.design.widget.AppBarLayout
         android:background="#00000000">

         <android.support.design.widget.CollapsingToolbarLayout
            app:layout_scrollFlags="scroll|exitUntilCollapsed">

             <com.android.myapp.MyCoolView
                app:layout_collapseMode="parallax"/>

         </android.support.design.widget.CollapsingToolbarLayout>

    </android.support.design.widget.AppBarLayout>

    <android.support.v7.widget.RecyclerView/>

</android.support.design.widget.CoordinatorLayout>

回答1:


Possible solution (untested). Add an OnOffsetChangedListener to your AppBarLayout, and keep note of the offset value. First, declare this field:

private boolean shouldScroll = false;

Then, onCreate:

AppBarLayout appbar = findViewById(...);
appbar.addOnOffsetChangedListener(new OnOffsetChangedListener() {
    @Override
    void onOffsetChanged(AppBarLayout appbar, int offset) {
        // Allow recycler scrolling only if we started collapsing.
        this.shouldScroll = offset != 0;
    }
});

Now, add a scroll listener to your RecyclerView. Whenever it tries to scroll, revert the scroll if the AppBarLayout is still expanded:

RecyclerView recycler = findViewById(...);
recycler.addOnScrollListener(new OnScrollListener() {
    @Override
    void onScrolled(RecyclerView recycler, int dx, int dy) {
        // If AppBar is fully expanded, revert the scroll.
        if (!shouldScroll) {
            recycler.scrollTo(0,0);
        }
    }
});

This might need some tweaking though. I see two issues:

  • Possible stack overflow if scrollTo() calls onScrolled() back. Can be solved with a boolean or by removing/adding the scroll listener
  • Possibly you want to prevent scrolling not only when AppBarLayout is fully expanded, but more generally when AppBarLayout is not collapsed. This means you don’t have to check for offset != 0, but rather for offset == appBarLayout.getTotalScrollRange(). I think.



回答2:


Maybe you can add layout_behavior="@string/appbar_scrolling_view_behavior" to your RecylerView like this.

<android.support.v7.widget.RecyclerView
        android:layout_width="match_parent"
        android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior" />



回答3:


Wrapping the RecyclerView in a FrameLayout solves this problem.

You also need move the appbar_scrolling_view_behavior from the RecyclerView to the FrameLayout so it will be positioned below the AppBarLayout properly.

<android.support.design.widget.CoordinatorLayout>

    <android.support.design.widget.AppBarLayout
        android:background="#00000000">

        <android.support.design.widget.CollapsingToolbarLayout
            app:layout_scrollFlags="scroll|exitUntilCollapsed">

            <com.android.myapp.MyCoolView
               app:layout_collapseMode="parallax"/>

        </android.support.design.widget.CollapsingToolbarLayout>

    </android.support.design.widget.AppBarLayout>

    <!-- BEGIN SOLUTION -->
    <!-- the layout behavior needs to be set on the FrameLayout, not the RecyclerView -->
    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"
        >

        <!--This RecyclerView MUST be wrapped in a FrameLayout-->
        <!--This prevents the RecyclerView from going behind the AppBarLayout-->
        <android.support.v7.widget.RecyclerView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            />

    </FrameLayout>
    <!-- END SOLUTION -->

</android.support.design.widget.CoordinatorLayout>


来源:https://stackoverflow.com/questions/37737187/prevent-recyclerview-from-scrolling-under-appbarlayout-before-appbarlayout-is-co

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!