I want to implement an app bar with a Recyclerview like the one in Gmail and Play store as below:
I tried using AppBarLayout inside a CoordinatorLayout but the App Bar is above the Recyclerview
However, I want it to be like an overlay so if it is transparent or have some margin, the recyclerview content show beneath like this:
I tried putting the app bar in a Relative layout with the recyclerview, but it does not hide when I scroll down (always fixed on the top even when using scroll flags).
This is my XML code:
<?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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".fragment.MainFragment"
android:background="#color/lightBackground">
<RelativeLayout
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="#+id/bottom_navigation"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.fragment.app.FragmentContainerView
android:id="#+id/tab_fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"/>
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="#dimen/main_action_bar_size"
android:background="#color/white">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
app:layout_scrollFlags="scroll|enterAlways|snap">
<FrameLayout
android:id="#+id/appBarDrawer"
android:layout_width="#dimen/main_action_bar_size"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:src="#drawable/ic_menu" />
</FrameLayout>
<FrameLayout
android:id="#+id/appBarSearch"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toRightOf="#+id/appBarDrawer"
app:layout_constraintRight_toLeftOf="#+id/appBarVoiceSearch"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:maxLines="2"
android:text="#string/search"
android:textColor="#color/lightGrayFont"
android:textSize="15sp" />
</FrameLayout>
<FrameLayout
android:id="#+id/appBarVoiceSearch"
android:layout_width="#dimen/main_action_bar_size"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toLeftOf="#+id/appBarMore"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:src="#drawable/ic_mic_none" />
</FrameLayout>
<FrameLayout
android:id="#+id/appBarMore"
android:layout_width="#dimen/main_action_bar_size"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:src="#drawable/ic_more" />
</FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.appbar.AppBarLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</RelativeLayout>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/bottom_navigation"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:menu="#menu/menu_bottom_navigation"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
I also what it to snap when it hides or shows without affecting the recyclerview scroll like the one in Play Store (seems to be in a deferent layer).
If you look, it's actually a cardview being used as the app bar layout. Something like this should get you what you're looking for:
<android.support.design.widget.CoordinatorLayout
android:id="#+id/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.CardView
android:layout_margin="16dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.design.widget.AppBarLayout
android:id="#+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_scrollFlags="scroll|enterAlways"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light"/>
</android.support.design.widget.AppBarLayout>
</android.support.v7.widget.CardView>
(sorry i don't remember android x libraries off the top of my head, for reference here is the link to find them https://developer.android.com/jetpack/androidx/migrate/artifact-mappings)
Related
I've seen answers from this thread, but I'm wondering if it's possible to do this in XML by adding a button component.
Earlier I had a button wrapped within a CardView, which will float as the users scrolling the RecyclerView, so I had a lot of code associated with this button. But now I need to make this button stay at the bottom of the screen instead of floating. I've tried to add another level of LinearLayout or even change the CoordinatorLayout to LinearLayout, but none of these worked.
Here's my original 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:id="#+id/ui_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.pages.MainActivity">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="#dimen/appbar_padding_top"
android:theme="#style/AppTheme.AppBarOverlay">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="#dimen/action_bar_height"
app:contentInsetEnd="0dp"
app:contentInsetStart="0dp"
app:popupTheme="#style/AppTheme.PopupOverlay">
<include layout="#layout/common_toolbar_with_buttons" />
</androidx.appcompat.widget.Toolbar>
<android.common.view.indicator.LoadingIndicatorBar
android:layout_width="match_parent"
android:layout_height="0dp"
android:visibility="visible" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/ui_attribute_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:paddingBottom="#dimen/item_input_attribute_list"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
<androidx.cardview.widget.CardView
android:id="#+id/ui_button_next_container"
android:layout_width="match_parent"
android:layout_height="#dimen/button_height_normal"
android:layout_gravity="center_horizontal|bottom"
android:layout_margin="24dp"
android:layout_marginBottom="8dp"
app:cardBackgroundColor="#color/colorAccent_Light"
app:cardElevation="12dp"
app:cardPreventCornerOverlap="true"
app:layout_dodgeInsetEdges="bottom">
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/pointed_gradient" />
<android.common.view.tint.TintFancyButton
android:id="#+id/ui_button_next"
style="#style/TransparentButtonStyle"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="#string/msg_save_current_input"
android:textAllCaps="true"
android:textSize="16sp"
android:textStyle="bold"
app:fb_borderColor="#2fffffff"
app:fb_borderWidth="2dp"
app:fb_defaultColor="#color/transparent"
app:fb_focusColor="#color/colorAccent_Light"
app:fb_textColor="#FFF" />
</androidx.cardview.widget.CardView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
Take a constraint layout outside of your recycler view and button and then make the button app:layout_constraintTop_toBottomOf="#id/recyclerview" in xml. Or you can also use linear layout in place of constraint layout, and set android:orientation="vertical".
This is the code.
<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:id="#+id/ui_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="20dp"
>
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="#dimen/Textsize25"
app:contentInsetEnd="0dp"
app:contentInsetStart="0dp"
>
</androidx.appcompat.widget.Toolbar>
<android.common.view.indicator.LoadingIndicatorBar
android:layout_width="match_parent"
android:layout_height="0dp"
android:visibility="visible" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/ui_attribute_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false"
android:paddingBottom="25dp"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="#+id/ui_button_next_container"
app:layout_constraintVertical_bias="0.05"/>
<androidx.cardview.widget.CardView
android:id="#+id/ui_button_next_container"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_gravity="center_horizontal|bottom"
android:layout_margin="24dp"
android:layout_marginBottom="8dp"
app:cardElevation="12dp"
app:cardPreventCornerOverlap="true"
app:layout_dodgeInsetEdges="bottom"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintVertical_bias="1">
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
<Button
android:id="#+id/ui_button_next"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="#string/msg_save_current_input"
android:textAllCaps="true"
android:textSize="16sp"
android:textStyle="bold"
/>
</androidx.cardview.widget.CardView>
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
I would recommend using a constraint layout to position all of your views.
In order to get the RecyclerView to fill the space between the top View and Button View. You'll need to use a match constraint for the RecyclerView height. To make the RecyclerView match the constraint height set the layout_height to 0dp.
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/ui_attribute_list"
android:layout_width="match_parent"
android:layout_height="0dp"
android:clipToPadding="false"
android:paddingBottom="25dp"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
app:layout_constraintBottom_toTopOf="#+id/ui_button_next_container"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.05" />
I know we can hide bottomnavigation and app bar on scroll when both are the direct children of coordinate layout, But my issue is different, I have one home fragment and bottom view is a part of this fragment with FragmentContainerView, now my app bar inside the fragment which i am setting in container view, when i am scrolling, app bar getting scroll properly but i am not sure how to scroll bottom navigation as well,
home_fragment:
<?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"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.fragment.app.FragmentContainerView
android:id="#+id/rootFragmentContainer"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="#+id/bottomNavigationView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/bottomNavigationView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:itemIconTint="#drawable/nav_bar_tab_color"
android:background="?android:attr/windowBackground"
app:itemTextAppearanceActive="#style/navText"
app:itemTextAppearanceInactive="#style/navText"
app:itemTextColor="#drawable/nav_bar_tab_color"
app:labelVisibilityMode="unlabeled"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:menu="#menu/navigation_items" />
</androidx.constraintlayout.widget.ConstraintLayout>
another fragment:
<?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">
<ProgressBar
android:id="#+id/progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
/>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/layout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="#id/appbar"
app:layout_behavior="#string/appbar_scrolling_view_behavior" >
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rvLay"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="#+id/rvProgressBar"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ProgressBar
android:id="#+id/rvProgressBar"
android:visibility="gone"
android:layout_width="0dp"
android:layout_height="50dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:background="#color/colorWhite"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_collapseMode="pin"
app:layout_scrollFlags="scroll|enterAlways"
app:popupTheme="#style/ThemeOverlay.AppCompat" >
<androidx.appcompat.widget.AppCompatTextView
android:id="#+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="#dimen/twentyfour_24dp"
android:paddingBottom="#dimen/eighteen_18dp"
android:text="#string/t2"
android:gravity="center"
android:textAllCaps="true"
style="#style/text_16px_franklin_gothic_normal_" />
</androidx.appcompat.widget.Toolbar>
</com.google.android.material.appbar.AppBarLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
Can some one please explain me, how to achieve it?
Have you tried to add app:layout_behavior="#string/hide_bottom_view_on_scroll_behavior" inside your BottomNavigationView? In my case, it works just fine :)
I also suggest you to use CoordinatorLayout instead of ConstraintLayout in your home_fragment.xml
I want to place a FrameLayout for hosting Fragments, a BottomNavigationView and a FAB inside a CoordinatorLayout. I would like to display a Snackbar over the BottomNavigationView and FAB to move up and down to accommodate the Snackbar. I have come up with the following layout but I am unable to get Snackbar and FAB behavior correctly.
<?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:id="#+id/main_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".landingpage.MainActivity">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
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:popupTheme="#style/AppTheme.PopupOverlay" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/content_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<FrameLayout
android:id="#+id/fragment_cont"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="#id/bottom_navigation"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/bottom_navigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:menu="#menu/bottom_main_activity_menu" />
</androidx.constraintlayout.widget.ConstraintLayout>
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
android:id="#+id/extended_fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_marginEnd="16dp"
android:layout_marginBottom="72dp"
android:contentDescription="#string/cont_desc"
android:text="#string/chat"
app:icon="#drawable/ic_baseline_chat_24" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
If I set LayoutParams like in this post then that margin 72dp margin is also displayed throwing FAB way up in the layout. If I don't use the margin the FAB will be stacked over the BottomNavigationView. I can use addCallback to set FAB margins programattically. Then also it will jump and then align itself to the right position. Overall it is not a good experience UX wise.
I would like to display a Snackbar over the BottomNavigationView
and FAB to move up and down to accommodate the Snackbar. I have come
up with the following layout but I am unable to get Snackbar and FAB
behavior correctly.
You get a bad behavior because you're trying to achieve something which is not common or maybe, not implemented this way by using BottomNavigationView and FAB together. It's actually more common to use FAB & BottomAppBar at the bottom of a layout.
Then also it will jump and then align itself to the right position.
Overall it is not a good experience UX wise.
Although it's not a good experience for users from a UX view, however, here are the approaches I may suggest:
Best approach : Using another CoordinatorLayout inside LinearLayout (Supported the FAB animation):
Code:
<?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:id="#+id/main_layout"
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:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:title="Test" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
android:id="#+id/content_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<FrameLayout
android:id="#+id/fragment_cont"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</androidx.core.widget.NestedScrollView>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="#+id/SnackBar"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
android:id="#+id/extended_fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="16dp"
android:text="Chat"
android:textColor="#color/white"
app:icon="#drawable/ic_baseline_send_24"
app:iconTint="#color/white" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/bottom_navigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
app:layout_insetEdge="bottom"
app:menu="#menu/escrow_menu" />
</LinearLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
And in Kotlin side:
extended_fab.setOnClickListener {
val snack: Snackbar = Snackbar.make(SnackBar, " Successfully ...!", Snackbar.LENGTH_SHORT)
snack.show()
}
2. BottomAppBar & FAB & setAnchorView() method without FAB animation
Anchored to FAB
Code:
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/coordinator"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<androidx.core.widget.NestedScrollView
android:id="#+id/content_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<!-- your FrameLayout maybe -->
<Button
android:id="#+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal|center"
android:text="SHOW SnakeBar"
app:layout_anchor="#+id/content_layout"
app:layout_anchorGravity="center" />
</androidx.core.widget.NestedScrollView>
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:title="Test" />
</com.google.android.material.appbar.AppBarLayout>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="true"
android:focusable="true"
app:layout_anchor="#id/bar" />
<com.google.android.material.bottomappbar.BottomAppBar
android:id="#+id/bar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:layout_gravity="bottom"
android:backgroundTint="#color/colorPrimaryDark">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
style="?android:attr/borderlessButtonStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="?android:attr/selectableItemBackground"
android:drawableTop="#drawable/ic_baseline_send_24"
android:gravity="center"
android:orientation="vertical"
android:text="Personal"
android:textColor="#FFFFFF">
</TextView>
<TextView
style="?android:attr/borderlessButtonStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="?android:attr/selectableItemBackground"
android:drawableTop="#drawable/ic_baseline_send_24"
android:gravity="center"
android:orientation="vertical"
android:text="Personal"
android:textColor="#FFFFFF">
</TextView>
<TextView
style="?android:attr/borderlessButtonStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="?android:attr/selectableItemBackground"
android:drawableTop="#drawable/ic_baseline_send_24"
android:gravity="center"
android:orientation="vertical"
android:textColor="#FFFFFF"
android:visibility="invisible">
</TextView>
<TextView
style="?android:attr/borderlessButtonStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="?android:attr/selectableItemBackground"
android:drawableTop="#drawable/ic_baseline_send_24"
android:gravity="center"
android:orientation="vertical"
android:text="Personal"
android:textColor="#FFFFFF">
</TextView>
<TextView
style="?android:attr/borderlessButtonStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="?android:attr/selectableItemBackground"
android:drawableTop="#drawable/ic_baseline_send_24"
android:gravity="center"
android:orientation="vertical"
android:text="Personal"
android:textColor="#FFFFFF">
</TextView>
</LinearLayout>
</com.google.android.material.bottomappbar.BottomAppBar>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
3. Using FAB - BottomNavigationView - ConstraintLayout without FAB animation
Code:
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/floating_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:layout_margin="16dp"
app:backgroundTint="#color/colorPrimary"
app:elevation="10dp"
app:layout_constraintBottom_toTopOf="#id/navigation"
app:layout_constraintLeft_toRightOf="#id/navigation"
app:layout_constraintRight_toLeftOf="#id/navigation"
app:layout_constraintTop_toBottomOf="#id/navigation"
app:layout_constraintTop_toTopOf="#id/navigation"
app:layout_insetEdge="bottom" />
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/navigation"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="#color/colorPrimaryDark"
android:visibility="visible"
app:itemIconTint="#color/white"
app:itemTextColor="#color/white"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:menu="#menu/escrow_menu" />
<Button
android:id="#+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="290dp"
android:layout_marginBottom="485dp"
android:text="Button"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Current unexpected behaviour:
Required scrolling behaviour:
I’m experiencing some unexpected scrolling behaviour in an Android Kotlin app with a scrolling "prominent top app bar”. The desired behavior is for the whole contents of the inner fragment (with layout defined in fragment_trains.xml) to scroll as soon as the user scrolls down on that part of the screen.
The prominent top app bar starts scrolling immediately as intended. The unexpected scrolling behaviour is that there is a delay in the inner fragment contents scrolling. They don’t start scrolling until the prominent top app bar has completed scrolling and reached it’s “condensed” smaller size. How is it possible to resolve this issue? Solutions I have tried include adding focus tags to various parts of the layout, but haven’t been able to find any other answers related to this issue.
See layout XML, and screen recording showing the issue. The inner fragment should begin to scroll immediately rather than be delayed until the "prominent top app bar” has rested in to it’s smaller position. Even if it’s not possible to provide a solution to directly fix this, I haven’t been able to find example of an app layout like this with material design with a scrolling "prominent top app bar” and bottom navigation bar and a fragment in between with a scrolling behaviour. Thanks.
activity_main.xml:
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:id="#+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:defaultNavHost="true"
app:layout_constraintBottom_toTopOf="#id/nav_view"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="#+id/appbar"
app:navGraph="#navigation/mobile_navigation" />
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/appbar"
android:layout_width="match_parent"
android:layout_height="128dp"
app:liftOnScroll="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:focusable="false"
app:liftOnScrollTargetViewId="#id/nav_host_fragment">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:expandedTitleMarginStart="28dp"
app:expandedTitleMarginBottom="28dp"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
app:contentScrim="?attr/colorPrimary"
app:statusBarScrim="?attr/colorPrimaryVariant"
app:expandedTitleTextAppearance="#style/Trains.TextAppearance.MaterialComponents.Headline6"
app:collapsedTitleTextAppearance="#style/Trains.TextAppearance.MaterialComponents.Headline6">
<com.google.android.material.appbar.MaterialToolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_scrollFlags="scroll|enterAlways|snap"
android:minHeight="80dp"
android:elevation="0dp"
android:title="#string/app_name"
app:layout_collapseMode="pin"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:menu="#menu/top_app_bar"
style="#style/Widget.MaterialComponents.Toolbar.Primary"/>
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/nav_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/colorPrimary"
app:itemIconTint="#color/bnv_tab_item_foreground"
app:itemTextColor="#color/bnv_tab_item_foreground"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:layout_gravity="bottom"
app:menu="#menu/bottom_nav_menu" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
fragment_trains.xml:
<androidx.core.widget.NestedScrollView xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toTopOf="#+id/nav_view"
android:background="#color/colorBackground">
<LinearLayout
android:id="#+id/temp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="128dp"
android:orientation="vertical">
<!-- Travel info section -->
<TextView
android:id="#+id/text_travelinfoheader"
style="#style/TrainMediumCaption"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="29dp"
android:layout_marginLeft="29dp"
android:layout_marginTop="29dp"
android:layout_marginEnd="29dp"
android:layout_marginRight="29dp"
android:gravity="start"
android:textAlignment="gravity"
app:layout_constraintEnd_toEndOf="parent"
/>
<com.google.android.material.card.MaterialCardView
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="#+id/travelinfocard"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="9dp"
android:layout_marginBottom="9dp"
android:layout_marginLeft="12dp"
android:layout_marginRight="12dp"
card_view:cardCornerRadius="4dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:cardElevation="1dp"
app:layout_constraintTop_toBottomOf="#+id/text_travelinfoheader">
<TextView
android:id="#+id/text_travelinfo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="19dp" />
</com.google.android.material.card.MaterialCardView>
<!-- Next trains section -->
<TextView
android:id="#+id/text_nexttrainheader"
style="#style/TrainMediumCaption"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="29dp"
android:layout_marginLeft="29dp"
android:layout_marginTop="9dp"
android:layout_marginEnd="29dp"
android:layout_marginRight="29dp"
android:gravity="start"
android:textAlignment="gravity"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/travelinfocard" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/nextrains_recyclerview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="9dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/text_nexttrainheader" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
To fix this issue, with the scrolling behaviour, this code:
app:layout_behavior="#string/appbar_scrolling_view_behavior"
needs to be moved from the NestedScrollView element in the fragment_trains.xml file, to the fragment element in the activity_main.xml file. Here are the new xml layout files to fix this issue:
New activity_main.xml:
<?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:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/appbar"
android:layout_width="match_parent"
android:layout_height="128dp"
app:liftOnScroll="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:focusable="false"
app:liftOnScrollTargetViewId="#id/nav_host_fragment"
>
<com.google.android.material.appbar.CollapsingToolbarLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:expandedTitleMarginStart="28dp"
app:expandedTitleMarginBottom="28dp"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
app:contentScrim="?attr/colorPrimary"
app:statusBarScrim="?attr/colorPrimaryVariant"
app:expandedTitleTextAppearance="#style/Train.TextAppearance.MaterialComponents.Headline6"
app:collapsedTitleTextAppearance="#style/Train.TextAppearance.MaterialComponents.Headline6">
<com.google.android.material.appbar.MaterialToolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_scrollFlags="scroll|enterAlways|snap"
android:minHeight="80dp"
android:elevation="0dp"
android:title="#string/app_name"
app:layout_collapseMode="pin"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:menu="#menu/top_app_bar"
style="#style/Widget.MaterialComponents.Toolbar.Primary"
/>
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<fragment
android:id="#+id/nav_host_fragment"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
android:layout_marginBottom="110dp"
app:navGraph="#navigation/mobile_navigation" />
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/nav_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/colorPrimary"
app:itemIconTint="#color/bnv_tab_item_foreground"
app:itemTextColor="#color/bnv_tab_item_foreground"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:layout_gravity="bottom"
app:menu="#menu/bottom_nav_menu" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
New fragment_trains.xml:
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/colorBackground">
<LinearLayout
android:id="#+id/temp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!-- Travel info section -->
<TextView
android:id="#+id/text_travelinfoheader"
style="#style/TrainMediumCaption"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="29dp"
android:layout_marginLeft="29dp"
android:layout_marginTop="29dp"
android:layout_marginEnd="29dp"
android:layout_marginRight="29dp"
android:gravity="start"
android:textAlignment="gravity"
app:layout_constraintEnd_toEndOf="parent"
/>
<com.google.android.material.card.MaterialCardView
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="#+id/travelinfocard"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="9dp"
android:layout_marginBottom="9dp"
android:layout_marginLeft="12dp"
android:layout_marginRight="12dp"
card_view:cardCornerRadius="4dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:cardElevation="1dp"
app:layout_constraintTop_toBottomOf="#+id/text_travelinfoheader">
<TextView
android:id="#+id/text_travelinfo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="19dp" />
</com.google.android.material.card.MaterialCardView>
<!-- Next trains section -->
<TextView
android:id="#+id/text_nexttrainheader"
style="#style/TrainMediumCaption"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="29dp"
android:layout_marginLeft="29dp"
android:layout_marginTop="9dp"
android:layout_marginEnd="29dp"
android:layout_marginRight="29dp"
android:gravity="start"
android:textAlignment="gravity"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/travelinfocard" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/nextrains_recyclerview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="9dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/text_nexttrainheader" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
Here is the result, with the correct scrolling behaviour:
As you can see above, when I scroll from 'Foliage Plants', the CollapsibleToolbar collapses as expected but when I drag from any product image, the page scrolls beneath AppBarLayout. Why is this happening and how to fix this? Ive tried setting VerticalRecyclerView.setNestedScrolling to false but that didn't work.
My home page layout is structured as follows
Structure of fragment located inside ViewPager
Layout of homepage
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.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.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.design.widget.CollapsingToolbarLayout
android:id="#+id/collapsing_toolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:contentScrim="?attr/colorPrimary"
app:layout_scrollFlags="scroll|exitUntilCollapsed|enterAlways"
app:titleEnabled="false">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar_productdetail"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light"/>
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerview_home_categoryfooter"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="?attr/actionBarSize"
app:layout_collapseMode="parallax"
app:layout_collapseParallaxMultiplier="1.0"/>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/search_background_list"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<ProgressBar
android:id="#+id/progressbar_home_loading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"/>
<TextView
android:id="#+id/textview_home_status"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/search_background_list"
android:gravity="center"
android:text="No Results Found"
android:visibility="invisible"/>
<experttag.nurserylive.util.ui.widget.CustomViewPager
android:id="#+id/viewpager_home"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<fragment
android:id="#+id/fragment_search"
android:name="experttag.nurserylive.fragment.SearchFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>
</android.support.design.widget.CoordinatorLayout>
Layout of the fragment inside ViewPager is as follows
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerview_productoverview"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/windowBackground"/>
Layout of item inside #id/recyclerview_productoverview
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
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="wrap_content">
<android.support.constraint.ConstraintLayout
android:id="#+id/layout_section_header"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="#ccc"
android:paddingBottom="10dp"
android:paddingTop="10dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent">
<experttag.nurserylive.util.ui.widget.WhitneySemiBoldTextView
android:id="#+id/textview_item_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="0dp"
android:layout_marginEnd="16dp"
android:layout_marginLeft="0dp"
android:layout_marginRight="0dp"
android:layout_marginStart="16dp"
android:layout_marginTop="0dp"
android:text="TOP FEATURED"
android:textColor="#000"
android:textSize="16sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<ImageView
android:id="#+id/imageview_item_viewall"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="?attr/selectableItemBackgroundBorderless"
android:clickable="true"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:tint="#000"
app:layout_constraintRight_toRightOf="parent"
app:srcCompat="#drawable/ic_arrow_forward_black_24dp"/>
</android.support.constraint.ConstraintLayout>
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerview_item_section"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="#+id/layout_section_header"/>
</android.support.constraint.ConstraintLayout>
setNestedScrollingEnabled(false) on inner Horizontal RecyclerView solved this problem for me.