4

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.

user158
  • 12,852
  • 7
  • 62
  • 94
  • does the things work as expected when there is no app bar layout? – user158 Mar 02 '19 at 11:08
  • Yes it works completely fine without app bar layout. Basic problem is that scroll flag is used in app bar layout. It is consuming scroll event required for bottom navigation behaviour. – Robin Sharma Mar 02 '19 at 11:24
  • 1
    Does provided answer works for you, if not what is the issue? – user158 Mar 02 '19 at 15:18

2 Answers2

3

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)
            }
        })
    }
user158
  • 12,852
  • 7
  • 62
  • 94
  • Thanks for the solution. It works but I think there must be some better solution for this problem. I need this behaviour in all of my 5 fragments of activity, then I have to apply this listener to all recycler views of 5 fragments. It would be great if there is some flag or anything else such that bottomnavigation is able to get scroll events (even if fragment uses app bar layout with scroll flags) as behaviour to hide/show bottomNav is already defined (just need to get scroll events directly). This functionality is present in Cricbuzz app, I wonder how they have done it – Robin Sharma Mar 03 '19 at 17:11
  • I think you may be able to extract the code to a separate function. – user158 Mar 04 '19 at 02:54
  • have you tried moving listener code to separate fn? – user158 Mar 06 '19 at 02:38
0

Update your library to 28.0.0 or above or the androidx / material-1.0.0 and change your BottomNavigationView like the below-

<BottomNavigationView
        android:id="@+id/navigation"
        .
        .
        .
        .
        app:layout_behavior="@string/hide_bottom_view_on_scroll_behavior" />

hope it will be helpful.

D_Alpha
  • 4,039
  • 22
  • 36