I'm having difficulties getting AppBarLayout, NestedScrollView and BottomNavigationView working together properly. My problem is that when I set app:layout_behavior="#string/appbar_scrolling_view_behavior" on the NestedScrollView, it extends behind the BottomNavigationView as illustrated here.
So the issue is that the BottomNavBar overlays the content, instead of the content stopping at the top of the Nav.
I've tried many solutions, including wrapping the layout in a RelativeLayout and putting the BottomNavView in that instead of the CoordinatorLayout.
Here's the basic layout from the sample project I've attached.
<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="com.example.android.navigationadvancedsample.MainActivity">
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/app_bar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:elevation="0dp">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_scrollFlags="scroll|enterAlways" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
android:id="#+id/app_scroll_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
android:fillViewport="true">
<FrameLayout
android:id="#+id/nav_host_container"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
</androidx.core.widget.NestedScrollView>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/bottom_nav"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
app:menu="#menu/bottom_nav"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
Here's a small sample project that reproduces the issue (based on the Navigation components sample from Google). Can someone please tell me what I'm doing wrong?
You just have to take BottomNavigationView out of the CoordinatorLayout and put both inside a RelativeLayout.
I was facing same problem and found the solution here. Hope it helps.
In your code, your NestedScrollView was taking up the whole screen. Using a vertical LinearLayout with weights you can make it to where the NestedScrollView stops at the top of the NavBar like you want.
<androidx.core.widget.NestedScrollView
android:id="#+id/app_scroll_view"
android:layout_width="match_parent"
android:layout_height="0dp" *** changed from match_parent to 0dp
android:layout_weight="1" *** added weight to fill remaining screen
app:layout_behavior="#string/appbar_scrolling_view_behavior"
android:fillViewport="true">
<FrameLayout
android:id="#+id/nav_host_container"
android:layout_width="match_parent"
android:layout_height="match_parent"/> *** changed from 0dp to match_parent
</androidx.core.widget.NestedScrollView>
The way it now is set up takes into account the NavBar and expands the layout of the NestedScrollView to fill the remaining empty space on the screen. Now the NestedScrollView will not expand beyond the NavBar.
Not sure . But seem like working in preview . Putting nestedScrollView and BottomNavigation view inside a relative layout .
<RelativeLayout android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.core.widget.NestedScrollView
android:id="#+id/app_scroll_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="#+id/bottom_nav"
android:fillViewport="true" android:layout_marginBottom="-2dp">
<FrameLayout
android:id="#+id/nav_host_container"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
</androidx.core.widget.NestedScrollView>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/bottom_nav"
android:layout_alignParentBottom="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
app:menu="#menu/bottom_nav_menu"/>
</RelativeLayout>
Related
I made a simple layout in which there is a AppBarLayout (that doesn't scroll), some content in the middle, and a BottomSheet. This BottomSheet is actually a LinearLayout with a BottomSheetBehavior and inside has a RecyclerView.
This BottomSheet when expanded places the RecyclerView on top of the AppBarLayout. The problem is that, when the user tries to scroll this RecyclerView, the AppBarLayout below steals the scroll.
I'm leaving the layout code, but I uploaded the whole example project to GitHub with a GIF to illustrate.
Layout
<?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/coordinator_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/app_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:liftOnScroll="false">
<com.google.android.material.appbar.MaterialToolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:title="#string/app_name" />
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="match_parent"
android:layout_height="56dp"
android:background="?colorSurface"
android:gravity="center_vertical"
android:padding="16dp"
android:text="Subtitle"
android:textAppearance="?textAppearanceSubtitle1" />
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="match_parent"
android:layout_height="56dp"
android:background="?colorSurface"
android:gravity="center_vertical"
android:padding="16dp"
android:text="Subsubtitle"
android:textAppearance="?textAppearanceBody2" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="56dp"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
android:text="#string/lorem_ipsum"
android:textAppearance="?textAppearanceBody1" />
</androidx.core.widget.NestedScrollView>
<LinearLayout
android:id="#+id/bottom_sheet_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="bottom"
android:background="#FFF"
android:elevation="5dp"
android:orientation="vertical"
app:behavior_hideable="false"
app:behavior_peekHeight="64dp"
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">
<androidx.appcompat.widget.AppCompatTextView
android:id="#+id/bottom_sheet_header"
android:layout_width="match_parent"
android:layout_height="64dp"
android:gravity="center_vertical"
android:padding="16dp"
android:text="Fruits"
android:textAppearance="?textAppearanceHeadline6" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
</LinearLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
I've tried:
Placing the nestedScrollingEnabled attribute in various places, but didn't work and this behavior occurs in old APIs (like JellyBean);
In the original project where I saw this I wrote a custom AppBarLayout behavior to ignore if the target View is the RecyclerView of the BottomSheet, but also didn't work;
Set the whole AppBarLayout GONE when the BottomSheet is expanded and funny enough the AppBarLayout behaves like I set to INVISIBLE (if programmatically set to GONE, it behaves like invisible, if set before inflating, it behaves as expected).
I'm avoiding use a Fragment to create this BottomSheet due to project specifications.
The workaround I did was split the CoordinatorLayout in 2, where one contains the AppBarLayout and the NestedScrollView, and the other one contains the BottomSheet (LinearLayout).
The hierarchy, using the layout of the question as example, end up like this:
<FrameLayout>
<CoordinatorLayout>
<AppBarLayout>
<MaterialToolbar/>
<AppCompatTextView/>
<AppCompatTextView/>
</AppBarLayout>
<NestedScrollView>
<AppCompatTextView/>
</NestedScrollView>
</CoordinatorLayout>
<CoordinatorLayout>
<LinearLayout>
<AppCompatTextView/>
<RecyclerView/>
</LinearLayout>
</CoordinatorLayout>
</FrameLayout>
In my case this works because my BottomSheet doesn't need to coordinate any behavior with the other views.
I can't get the anchor to work. it doesn't follow the app bar being scrolled to the top.
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:background="#color/testGray">
<android.support.design.widget.AppBarLayout
android:id="#+id/appbar"
android:layout_width="match_parent"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_height="200dp"
android:layout_gravity="center_horizontal"
>
<android.support.design.widget.CollapsingToolbarLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
android:background="?attr/colorPrimary"
android:fitsSystemWindows="true"
app:contentScrim="?attr/colorPrimary"
>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<FrameLayout
android:id="#+id/frame_info"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_marginTop="140dp"
android:elevation="11dp"
android:layout_gravity="center_horizontal"
app:layout_anchor="#id/appbar"
app:layout_anchorGravity="center|bottom"
>
</FrameLayout>
<team.semicolon.amizeh.CustomViews.SongsListView
android:id="#+id/songs_listview"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintTop_toBottomOf="#id/frame_info"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginTop="60dp"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
/>
</android.support.design.widget.CoordinatorLayout>
</android.support.constraint.ConstraintLayout>
plus, I can't get the minHeight to work, It scrolls all the way to the top.
I want the frame layout to follow the app bar and anchor it but the app bar scrolls but the frame layout doesn't.
the frame_info doesn't follow the appbar when I scroll, as it was
supposed to do. when I scroll SongsListView to the top, the appbar
moves to the top too, but frame_info stays in place
First of all, i don't suggest such a layout. Like i said, make the CoordinatorLayout as the root of the layout.
Also, if you are trying to achieve FrameLayout follow AppbarLayout when scrolling, you'll need to add it inside a NestedScrollView then setting the NestedScrollView:
app:layout_behavior="#string/appbar_scrolling_view_behavior"
To follow AppbarLayout.
Check my answer about where to using above code : appbar_scrolling_view_behavior https://stackoverflow.com/a/35181870/4409113
I want to use
<android.support.v4.widget.NestedScrollView
android:id="#+id/scroll_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#id/action_bar"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:id="#+id/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:visibility="gone">
<RelativeLayout
android:id="#+id/image"
android:layout_width="match_parent"
android:layout_height="220dp">
<ImageView
android:id="#+id/cover_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"/>
</RelativeLayout>
<RelativeLayout
android:id="#+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#id/image"
android:background="#color/card_background">
<android.support.design.widget.TabLayout
android:id="#+id/topTabs"
style="#style/TextAppearance.Tab"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabBackground="#color/bpWhite"
app:tabGravity="fill"
app:tabMode="fixed"
app:tabTextColor="#color/secondary_text_color"
custom:tabIndicatorColor="#color/secondary_text_color"
custom:tabIndicatorHeight="2dp" />
<View
android:layout_width="match_parent"
android:layout_height="2dp"
android:layout_below="#id/topTabs"
android:background="#drawable/tab_layout_drop_shadow" />
</RelativeLayout>
<android.support.v4.view.ViewPager
android:id="#+id/viewPager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#id/tab_layout" />
</RelativeLayout>
</RelativeLayout>
</android.support.v4.widget.NestedScrollView>
It is not able to scroll, that view-pager or tab-layout is not able scroll I tried all the ways.
1.Disable the touch event in view-pager and enable the touch event for scroll-view.
2.Tried other scroll-views like Nestedscrollview, Parallaxscrollview, Coordinator layout.If I use coordinator layout then not able to change he toolbar.
I used fillviewport true for all the scrollviews. but still it is not able to scroll.
Any Other ways to fix the issue.
You can use view pager without the toolbar, but you can't use the tabs without the toolbar.
Although it remains unclear, what you are trying to achieve here, there is no problem in the layout, really.
If you set up the Design Support Library correctly and
if you did not mess up your listeners with your attempts to disable some touch events and
if you take out the tools:visibility="gone" attribute (in order to show anything that can be scrolled) and
if you decide on a specific height (or wrap_content) for the ViewPager and
optionally if you take out the first RelativeLayouts which is unnecessary,
then you should be able to scroll. At least I am inside the layout editor of Android Studio.
When the activity is opened, it shows the top of the RecyclerView layout instead of the top of the activity layout.
Activity layout .xml file:
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingBottom="20dp"
android:paddingTop="20dp">
...
<RelativeLayout/>
<View />
<LinearLayout/>
...
<android.support.v7.widget.RecyclerView
android:id="#+id/venue_place_info_gallery_recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"/>
</LinearLayout>
</ScrollView>
Activity onCreate:
RecyclerView galleryRecyclerView = (RecyclerView) findViewById(R.id.venue_place_info_gallery_recycler_view);
galleryRecyclerView.setLayoutManager(new StaggeredGridLayoutManager(gridLayoutColumns, StaggeredGridLayoutManager.VERTICAL));
VenueGalleryAdapter venueGalleryAdapter = new VenueGalleryAdapter(VenuePlaceInfoActivity.this, images);
galleryRecyclerView.setAdapter(venueGalleryAdapter);
The adapter is very simple. It receives the images as an argument in the constructor and the data cannot be changed later on.
I've tried to apply all kinds of settings to the RecyclerView layout, but it works the same with or without them. For example:
galleryRecyclerView.setNestedScrollingEnabled(false);
galleryRecyclerView.setHasFixedSize(true);
galleryRecyclerView.setLayoutFrozen(true);
galleryRecyclerView.setPreserveFocusAfterLayout(false);
UPDATE:
I have found more info on the subject in the answer of another question. It's all because of the ScrollView and RecyclerView not being capable to live together even if you set setNestedScrollingEnabled to true. But it still doesn't give me the resolution of my problem. I need to have some stuff above the gallery RecyclerView and I want to scroll down through all the images (not putting them in a container).
If you want your layout to look good, I would use a CoordinatorLayout with an AppBarLayout as the first element inside it, and the RecyclerView as the second. Inside the AppBarLayout, you should put whatever it is that you would like to have above the RecyclerView. Something similar to this:
<LinearLayout
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:orientation="vertical">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="#color/white">
<android.support.design.widget.AppBarLayout
android:id="#+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:elevation="0dp">
<android.support.design.widget.CollapsingToolbarLayout
android:id="#+id/collapsing_toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_scrollFlags="scroll|enterAlways"
app:titleEnabled="false">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipChildren="false"
android:clipToPadding="false"
android:orientation="vertical"
android:paddingTop="20dp"
app:layout_collapseMode="parallax">
<!-- stuff you want above your recyclerview -->
</LinearLayout>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
app:layout_behavior="#string/appbar_scrolling_view_behavior"/>
</android.support.design.widget.CoordinatorLayout>
</LinearLayout>
Someone does something similar here, just instead of using a toolbar in the appbarlayout, you may use whatever view layouts you'd like. AppBarLayout is an extended Vertical LinearLayout: http://www.basagee.tk/handling-scrolls-with-coordinatorlayout/
just add the following tag on your activity/fragment root layout and you are good to go.
android:descendantFocusability="blocksDescendants"
I have 3 views in my layout file with CoordinatorLayout as the root view : AppbarLayout, RecyclerView and a Footer(not visible all the time). Recyclerview implements the default behavior appbar_scrolling_view_behavior, that ideally, brings recyclerview below the appbarlayout. But the recyclerview and footer overlap. To Prevent that, I had to write a custom behavior so that when footer is visible, Recyclerview should make space for the footer. But now, the default behavior of appbar_scrolling_view_behavior is gone and now appbarlayout and recyclerview overlap.Here is the Image of the layout
Link to the custom behavior i implemented:
https://github.com/Mandeep221/CustomBehaviorForRecyclerview/blob/master/CustomBehavior.java
My Question: How can i implement 2 things(simultaneously in one behavior):
get the recyclerview below the appbarlayout inside the co-ordinatorlayout
get the recycelerview to make space for the footer if the footer is visible.
If you can suggest some workaround, that would also be great! Thanks alot!
<android.support.design.widget.AppBarLayout
android:id="#+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
android:id="#+id/app_bar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:layout_scrollFlags="scroll|enterAlways|snap" />
</android.support.design.widget.AppBarLayout>
<android.support.v7.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/list_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="4dp"
android:scrollbars="vertical"
app:layout_behavior="prokure.it.prokure.Search.NewSearch.CustomBehavior" />
<prokure.it.prokure.FooterBarLayout
android:id="#+id/footerBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
//footer child views
</LinearLayout>
</prokure.it.prokure.FooterBarLayout>
</android.support.design.widget.CoordinatorLayout>
Don't keep the android.support.design.widget.CoordinatorLayout as root layout.
Add a RelativeLayout as a root layout. Then add android.support.design.widget.CoordinatorLayout with property layout_alignParentTop and layout_above="#+id/footerBar" and set prokure.it.prokure.FooterBarLayout as align parent bottom as second child of RelativeLayout.
<RelativeLayout
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.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_above="#+id/footerBar">
<android.support.design.widget.AppBarLayout
android:id="#+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
android:id="#+id/app_bar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:layout_scrollFlags="scroll|enterAlways|snap" />
</android.support.design.widget.AppBarLayout>
<android.support.v7.widget.RecyclerView
android:id="#+id/list_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="4dp"
android:scrollbars="vertical"
/>
</android.support.design.widget.CoordinatorLayout>
<prokure.it.prokure.FooterBarLayout
android:id="#+id/footerBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
//footer child views
</LinearLayout>
</prokure.it.prokure.FooterBarLayout>
</RelativeLayout>
Another simpler way is to add following lines to your prokure.it.prokure.FooterBarLayout
app:layout_anchor="#id/list_recycler_view"
app:layout_anchorGravity="bottom"
and keep prokure.it.prokure.FooterBarLayout inside coordinator layout.
Make sure to add an empty cell at the end of the recycler view so that prokure.it.prokure.FooterBarLayout does not overlap with last cell of RecyclerView.