Search code examples
androidscrollbottomnavigationviewandroid-appbarlayout

BottomNavigationView does not hide on scrolling inside fragment, if fragment contains AppBarLayout


I'm having a lot of problems with scrolling and detection of it inside fragments using coordinatorLayout in Android. I have a "MainActivity" that contains 3 fragments. In one of those fragments I have an Appbar that collapses when fragment is scrolled. I've managed to do that, but if I set scrolling behavior to allow that, my bottomNavigationView (which is found in mainactivity.xml) does NOT react to scrolling. Codes go something like this:

Fragment1.xml

<android.support.design.widget.CoordinatorLayout
...
...>
    <android.support.design.widget.AppBarLayout
 ...
 ...>
        <android.support.design.widget.CollapsingToolbarLayout
                 app:layout_scrollFlags="scroll|exitUntilCollapsed"
   ...>
            <android.support.v7.widget.Toolbar
     .../>
        </android.support.design.widget.CollapsingToolbarLayout>
    </android.support.design.widget.AppBarLayout>

   <android.support.v4.widget.NestedScrollView
        app:layout_behavior="@string/appbar_scrolling_view_behavior">
   </android.support.v4.widget.NestedScrollView>

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

MainActivity.xml

<android.support.design.widget.CoordinatorLayout
.../>
    <FrameLayout
        app:layout_behavior="@string/appbar_scrolling_view_behavior"
 .../>
    <android.support.design.widget.BottomNavigationView
      app:layout_behavior="@string/hide_bottom_view_on_scroll_behavior"
.../>
</android.support.design.widget.CoordinatorLayout>

Now, this works well enough, in the sense that when I scroll inside fragment my AppBar collapses into the title (which is what I want), BUT my bottomNavigationView does not react to scrolling.

What I found out is that if i add the line

app:layout_behavior="@string/appbar_scrolling_view_behavior"

to the AppBarLayout xml declaration I get the bottomView to collapse on scroll event (when I scroll up it shows again). So basically either I have the ability to collapse appbar inside fragment OR I have the ability to hide BottomNavigationView when I detect a scroll event inside the fragment.

Any sort of help would be appreciated.


Solution

  • In order to hide bottom navigation in reaction to scrolling inside the fragement modify onCreateView method on fragment1.kt as follows

    override fun onCreateView(
            inflater: LayoutInflater, container: ViewGroup?,
            savedInstanceState: Bundle?
        ): View? {
    
            ...
    
            // access the bottom nav which is on the main activity
            val bottomNav: BottomNavigationView = activity!!.findViewById(R.id.bottom_nav)
    
            // hide bottom nav when scrolling
            rvList.addOnScrollListener(object : RecyclerView.OnScrollListener() {
    
                override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
                    if (dy > 0 || dy < 0) {
                        bottomNav.visibility = View.GONE
                    }
                }
    
                override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
                    if (newState == RecyclerView.SCROLL_STATE_IDLE) {
                        bottomNav.visibility = View.VISIBLE
                    }
    
                    super.onScrollStateChanged(recyclerView, newState)
                }
            })
    
            return view
    }
    

    In Java

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
            ...
    
        // access the bottom nav which is on the main activity
        BottomNavigationView bottomNav = getActivity.findViewById(R.id.bottom_nav);
    
        // hide bottom nav when scrolling
        recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener()
        {
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy)
            {
                 if (dy > 0 ||dy<0)
                 {
                     bottomNav.setVisibility(View.GONE);
                 }
            }
    
            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState)
            {
                 if (newState == RecyclerView.SCROLL_STATE_IDLE)
                 {
                      bottomNav.setVisibility(View.VISIBLE);
                 }
    
                 super.onScrollStateChanged(recyclerView, newState);
            }
        });
    
            return view;
     }
    

    Update:

    Extract the listener code to a separate function as given below (in Kotlin)

       public fun hideBottomNav(
            rvList: RecyclerView,
            bottomNav: BottomNavigationView
        ) {
            rvList.addOnScrollListener(object : RecyclerView.OnScrollListener() {
    
                override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
                    if (dy > 0 || dy < 0) {
                        bottomNav.visibility = View.GONE
                    }
                }
    
                override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
                    if (newState == RecyclerView.SCROLL_STATE_IDLE) {
                        bottomNav.visibility = View.VISIBLE
                    }
    
                    super.onScrollStateChanged(recyclerView, newState)
                }
            })
        }