Search code examples
androidmaterial-designmdc-components

Android MDC: ExtendedFloatingActionButton shrink and Expand animations whilst scrolling loose the position of the component


I've created an EFAB that is a direct child of CoordinatorLayout. In the CoordinatorLayout there is a RecyclerView with a scroll listener that expands and shrinks the EFAB (I'm trying to replicate the m3 scrolling behaviors seen here). The EFAB is anchored to the bottom navigation view

The problem is that when the shrink/expand is triggered, if I'm scrolling fast, the button disappears (it goes behind my nav bar, it's as if the animations lost the position).

Calling shrink/expand whilst scrolling shouldn't affect at all the position of the fab (more so because it's positioned in the CoordinatorLayout and anchored on top of the bottom navigation)

Demonstration video

Source code:

class FabExtendingOnScrollListener(
    private val floatingActionButton: ExtendedFloatingActionButton
) : RecyclerView.OnScrollListener() {
    override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
        if (newState == RecyclerView.SCROLL_STATE_IDLE
            && !floatingActionButton.isExtended
            && recyclerView.computeVerticalScrollOffset() == 0
        ) {
            floatingActionButton.extend()
        }
        super.onScrollStateChanged(recyclerView, newState)
    }

    override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
        if (dy != 0 && floatingActionButton.isExtended) {
            floatingActionButton.shrink()
        }
        super.onScrolled(recyclerView, dx, dy)

The layout:

<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:openDrawer="start">

       
        <androidx.coordinatorlayout.widget.CoordinatorLayout
            android:id="@+id/cord_main_content"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:fitsSystemWindows="true"
            >
        
           <com.google.android.material.appbar.AppBarLayout
            android:id="@+id/appBarLayout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
               android:fitsSystemWindows="true">
           
            <com.google.android.material.appbar.CollapsingToolbarLayout
                    android:id="@+id/collapsingToolbarLayout"
                    app:titleEnabled="false"
                android:layout_width="match_parent"
                android:layout_height="wrap_content">
                
                <include
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                   layout="@layout/PartialToolbar"/>
                
                 <com.google.android.material.progressindicator.LinearProgressIndicator
                       android:id="@+id/topAppBarProgressBar"
                       android:layout_gravity="bottom"
                        android:layout_width="match_parent"
                       android:layout_height="wrap_content" 
                       app:hideAnimationBehavior="inward"
                       app:showAnimationBehavior="outward"
                    android:layout_marginTop="?attr/actionBarSize"
                        />
                  
            </com.google.android.material.appbar.CollapsingToolbarLayout>
            

        </com.google.android.material.appbar.AppBarLayout>

            <!-- In order to move it above the navigation view i dynamically add padding bottom-->
            <FrameLayout
            android:id="@+id/content_frame_shell"
            android:layout_width="match_parent"
            app:layout_behavior="@string/appbar_scrolling_view_behavior"
            android:layout_height="match_parent"/>
            

            <com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:id="@+id/fab_shell"
                app:icon="@drawable/ic_baseline_add_24"
                app:layout_anchor="@id/bottom_navigation"
                app:layout_anchorGravity="top|end"
            android:layout_gravity="top|end"
            android:layout_margin="@dimen/fab_margin"
                android:translationY="-16dp"
            />
            </LinearLayout>
            
            <com.google.android.material.bottomnavigation.BottomNavigationView
              android:id="@+id/bottom_navigation"
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
                        app:elevation="6dp"

              android:layout_gravity="bottom"
              android:fitsSystemWindows="true"
                app:labelVisibilityMode="labeled"
              />
        </androidx.coordinatorlayout.widget.CoordinatorLayout>
    
    
    

    <com.google.android.material.navigation.NavigationView
        android:id="@+id/nav_view"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:fitsSystemWindows="true" />

</androidx.drawerlayout.widget.DrawerLayout>

If I disable the Expanding and shrink behaviour this doesn't happen at all. It seems like it is a problem of the animation.

I have other screens where the EFAB is not anchored to a view but just hanging around at the bottom of the screen and this also doesn't happen. It seems to be very specific to the fact that the EFAB is anchored somewhere.


Solution

  • As a workaround you can create a new component that inherits from ExtendedFloatingActionButton and override the getBehavior function. Return null.

    With this, the issue dissappears and from looking at the source code it doesn't do anything of use for me right now.

    I've created a github issue in the material android repo to let them know, but for now this works