Static BottomNavigation inside CoordinatorLayout but not as direct child - android

I have top level container with CoordinatorLayout and Toolbar that hides when scolling, this container contain fragments.
<androidx.coordinatorlayout.widget.CoordinatorLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.screens.main.MainActivity">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:elevation="0dp"
android:theme="#style/AppTheme.AppBarOverlay">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:layout_scrollFlags="scroll|enterAlways"
app:popupTheme="#style/AppTheme.PopupOverlay" />
</com.google.android.material.appbar.AppBarLayout>
<include layout="#layout/content_main" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
One of my fragments contain RecycleView and BottomNavigation
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:pp="http://schemas.android.com/tools"
android:id="#+id/cl_content"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.core.widget.NestedScrollView
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.recyclerview.widget.RecyclerView/>
</androidx.core.widget.NestedScrollView>
<BottomNavigation />
</androidx.constraintlayout.widget.ConstraintLayout>
The problem that the BottomNavigation scrolls with the content, when the app start the BottomNavigation almost invisible, and when I scroll down the BottomNavigation became visible and vise versa, I need it to be static without scroll behavior, is there any configuration for that?
I guess the problem because BottomNavigation is not direct child of CoordinatorLayout but is there workaround?
Demo project(ignore slideshow and gallery):
https://github.com/pavelpoley/CoordinatorLayoutQuestion

Remove app:layout_behavior="#string/appbar_scrolling_view_behavior" from your content_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:showIn="#layout/app_bar_main">
</androidx.constraintlayout.widget.ConstraintLayout>
UPDATE: After demo project has been updated with a more complex hierarchy provided solution above didn't work as expected.
I did a lot of research and couldn't find any clean solution to have BottomNavigationView inside CoordinatorLayout but not as a direct child.
The only solution was to move BottomNavigationView inside CoordinatorLayout as a child and then change its visibility based on androidx.navigation.NavController destination.
Source code: https://github.com/dautovicharis/CoordinatorLayoutQuestion/commits/master

You can make a couple of changes
Add exitUntilCollapsed flag to the Toolbar
app:layout_scrollFlags="scroll|enterAlways|exitUntilCollapsed"
Remove the app:layout_behavior from the NestedScrollView, and add it to root ConstraintLayout
By applying those, the layouts will be:
<androidx.coordinatorlayout.widget.CoordinatorLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.screens.main.MainActivity">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:elevation="0dp"
android:theme="#style/AppTheme.AppBarOverlay">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:layout_scrollFlags="scroll|enterAlways|exitUntilCollapsed"
app:popupTheme="#style/AppTheme.PopupOverlay" />
</com.google.android.material.appbar.AppBarLayout>
<include layout="#layout/content_main" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
And fragment:
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:pp="http://schemas.android.com/tools"
android:id="#+id/cl_content"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.core.widget.NestedScrollView
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.recyclerview.widget.RecyclerView/>
</androidx.core.widget.NestedScrollView>
<BottomNavigation />
</androidx.constraintlayout.widget.ConstraintLayout>

Related

Android snackbar looks to be attached to a nested scrollview

I have a weird problem where the Snackbar is being attached to the scroll view, so when a user scrolls the snackbar moves with the scrolling instead of staying position on the bottom of the screen.
I know it's caused by how I've set up my layout but I don't know a solution to either better setup my layout, or stop this behavior.
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="#+id/collapse_toolbar"
style="?attr/collapsingToolbarLayoutMediumStyle"
android:layout_width="match_parent"
android:layout_height="?attr/collapsingToolbarLayoutMediumSize"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
app:title="">
<com.google.android.material.appbar.MaterialToolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:elevation="0dp"
app:layout_collapseMode="pin"
app:title="" />
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<androidx.fragment.app.FragmentContainerView
android:id="#+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
app:defaultNavHost="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="#navigation/nav_graph" />
</androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
As you can see I'm wrapping the FragmentContainerView inside of a NestedScrollView which works and allows the CollapsingToolbarLayout to work as expected, as well as the child fragments content to scroll as I want.
Each child fragment just implements a basic layout a bit like:
<androidx.coordinatorlayout.widget.CoordinatorLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
//... Lots of text views etc etc
</androidx.coordinatorlayout.widget.CoordinatorLayout>
I tried removing the top level NestedScrollView and implementing it at each fragment, but that caused lots of issues with the CollapsingToolbarLayout and the child fragment content overlapping etc.
Is there a more straightforward solution to this?
Thanks for any input

How to use Coordinatorlayout with Linearlayout?

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".activities.MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.google.android.material.appbar.MaterialToolbar
style="#style/Widget.MaterialComponents.Toolbar.Surface"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:elevation="4dp"
app:layout_behavior="com.google.android.material.behavior.HideBottomViewOnScrollBehavior"
app:title="#string/app_name" />
<androidx.fragment.app.FragmentContainerView
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
app:defaultNavHost="true" />
<com.google.android.material.bottomnavigation.BottomNavigationView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:labelVisibilityMode="unlabeled"
app:layout_behavior="com.google.android.material.behavior.HideBottomViewOnScrollBehavior"
app:menu="#menu/menu_bottom_navigation" />
</LinearLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
This attribute app:layout_behavior="com.google.android.material.behavior.HideBottomViewOnScrollBehavior" does not work inside LinearLayout, I tried to put BottomNavigationView outside LinearLayout, and the attribute above worked but I want to put FragmentContainerView above BottomNavigationView and at the same time make the attribute above work. How can I solve the problem?
Update your code like below:
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".activities.MainActivity">
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/abl"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/AppTheme.AppBarOverlay">
<com.google.android.material.appbar.MaterialToolbar
style="#style/Widget.MaterialComponents.Toolbar.Surface"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:elevation="4dp"
app:title="#string/app_name" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.fragment.app.FragmentContainerView
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
app:defaultNavHost="true" />
<com.google.android.material.bottomnavigation.BottomNavigationView
android:layout_gravity="bottom"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:labelVisibilityMode="unlabeled"
app:layout_behavior="#string/hide_bottom_view_on_scroll_behavior"
app:menu="#menu/menu_bottom_navigation" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
I found a simple trick to solve the problem. Inside FragmentContainerView I'm showing a specific fragment and there is NestedScrollView inside the fragment.
I gave these attributes to the NestedScrollView
android:clipToPadding="false"
android:paddingBottom="Should be the same height of BottomNavigationView"
Now the content inside FragmentContainerView will be top of BottomNavigationView and never will touch BottomNavigationView.
The disadvantages of this way
It will leave extra space in the bottom but mostly
BottomNavigationView will cover it
If you give background color for NestedScrollView, The color will
touch BottomNavigationView
But at least it is working as I want.

Toolbar extends when keyboard opens

I have a toolbar that is beneath the status bar. If I click on a TextInputLayout, the keyboard opens but my toolbar will extend as shown here (if the keyboard is closed, the Toolbar has the usual size):
My xml-files:
The toolbar:
<androidx.appcompat.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/backgroundColor"
android:fitsSystemWindows="true"
android:theme="#style/AppTheme.SubAppBarOverlay"
app:popupTheme="#style/AppTheme.PopupOverlay"
app:title="Title"
android:elevation="4dp" />
Where it is included:
<androidx.constraintlayout.widget.ConstraintLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/backgroundColor"
android:fitsSystemWindows="false"
tools:context=".EditDayActivity">
<include
android:id="#+id/sub_toolbar"
layout="#layout/sub_toolbar"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<RelativeLayout
android:id="#+id/scrollViewContainer"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/sub_toolbar"
android:fitsSystemWindows="false">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:fitsSystemWindows="true">
</ScrollView>
</RelativeLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
Try removing the android:fitsSystemWindows="true" from your toolbar
Edit:
Maybe you should use a coordinatorlayout instead and put your toolbar in there.
I had the same problem and eventually got around it by using CoordinatorLayout as my activity root with app:statusBarColor="#color/some_color" and moving android:fitsSystemWindows="true" there. Probably not the best solution but the only one that worked with my layout.
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".MyActivity"
app:statusBarBackground="#color/some_color">
...
</androidx.coordinatorlayout.widget.CoordinatorLayout>
I eventually managed to solve my problem by putting the ScrollView directly into the ConstraintLayout like this (and not using a RelativeLayout):
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/backgroundColor"
android:fitsSystemWindows="true"
tools:context=".MyActivity">
<include
... />
<ScrollView
... />
</androidx.constraintlayout.widget.ConstraintLayout>

RecyclerView last item is cut off onResume of fragment

Problem
RecyclerView functions properly and no view is cut when not opening a detailFragment. But it cuts off the last item of my RecylerView item whenever I return back from the detailFragment launched by the recylcerview item.
I only encounter this on my emulator which api 26. When I run it in my api 28 phone it works properly. But I think I might be missing something.
fragment_main
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:background="#color/colorWhite">
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/fragment_main_abl"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:elevation="0dp"
android:background="#color/colorWhite"
android:fitsSystemWindows="true">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="#+id/fragment_main_ctbl"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
app:contentScrim="#android:color/white"
app:expandedTitleTextAppearance="#color/colorPrimaryText"
android:fitsSystemWindows="true">
<include layout="#layout/header_fragment_main"
app:layout_collapseMode="parallax"/>
<androidx.appcompat.widget.Toolbar
android:id="#+id/fragment_main_tb"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin">
</androidx.appcompat.widget.Toolbar>
</com.google.android.material.appbar.CollapsingToolbarLayout>
<com.google.android.material.tabs.TabLayout
android:id="#+id/fragment_main_tl"
android:layout_width="match_parent"
android:layout_height="#dimen/fragment_main_tl_height"
app:tabMode="scrollable"
app:tabSelectedTextColor="#color/colorPrimary"
app:tabTextColor="#color/colorUnselected"/>
</com.google.android.material.appbar.AppBarLayout>
<androidx.viewpager.widget.ViewPager
android:id="#+id/fragment_main_vp"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
fragment_child
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="#android:color/white"
>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/fragment_child_rv"
android:layout_width="0dp"
android:layout_height="0dp"
android:clipToPadding="false"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
NOTE
I wish not to put bottom padding for my recyclerView. I have tried
this and it works but during the times that my recyclerView functions
properly an excess padding is seen at the bottom
I wish not to make use of nestedScrollView for my recyclerView if possible since I would like the recyclerView to recycle as much as possible
Replacing
app:layout_scrollFlags="scroll|exitUntilCollapsed"
with
app:layout_scrollFlags="scroll|enterAlways|enterAlwaysCollapsed"
solved my issue.

BottomNavigationView hidden by default after adding scroll behaviour

I have the following main layout and a recyclerview in my fragment. The problem i am facing is that the bottom navigation view is hidden by default and appears only when i scroll down the navigation view appears.
Before scrolling down
After scrolling down the bottomnavigationview appears
Another issue i am facing is that after scrolling down and changing the fragment the toolbar disappears
content_home.xml
<RelativeLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:context=".activity.HomeActivity"
tools:showIn="#layout/activity_home">
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/navigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="?android:attr/windowBackground"
app:itemIconTint="#drawable/nav_item_foreground"
app:itemTextColor="#drawable/nav_item_foreground"
app:layout_behavior="#string/hide_bottom_view_on_scroll_behavior"
app:menu="#menu/navigation" />
<FrameLayout
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="#+id/navigation" />
</RelativeLayout>
This is the main activity layout
activity_home.xml
<androidx.coordinatorlayout.widget.CoordinatorLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
>
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/appBar"
android:theme="#style/AppTheme.AppBarOverlay">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:layout_scrollFlags="scroll|enterAlways"
app:popupTheme="#style/AppTheme.PopupOverlay" />
</com.google.android.material.appbar.AppBarLayout>
<include
layout="#layout/content_home" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
There is an issue in your content_home.xmlYou are using app:layout_behavior="#string/hide_bottom_view_on_scroll_behavior" in BottomNavigationView.
That's why it is happing.
Remove hide_bottom_view_on_scroll_behaviorfrom app:layout_behavior.

Categories

Resources