The new BottomNavigationView from support library v25.0.0 is supposed to hide when scrolling down, in order to see all the items from a list. However, in my testing scenario, the view hides when scrolling up. Any ideas what can cause this reverse behavior?
The inner_fragment is set up as a Fragment inserted inside the activity_main_framelayout_content Framelayout. XML layouts below:
main_activity.xml:
<android.support.design.widget.CoordinatorLayout
android:id="#+id/activity_main_coordinatorlayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:id="#+id/activity_main_appbarlayout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
android:id="#+id/activity_main_toolbar"
android:layout_height="?attr/actionBarSize"
android:layout_width="match_parent"
android:background="?attr/colorPrimary"
app:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light"
app:layout_scrollFlags="scroll|enterAlways">
<include layout="#layout/activity_main_spinner_layout"/>
</android.support.v7.widget.Toolbar>
</android.support.design.widget.AppBarLayout>
<FrameLayout
android:id="#+id/activity_main_framelayout_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
android:fitsSystemWindows="true"/>
</android.support.design.widget.CoordinatorLayout>
<android.support.design.widget.NavigationView
android:id="#+id/activity_main_framelayout_navigation_drawer"
android:layout_width="#dimen/drawer_width"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
android:background="#color/color_black_700"/>
inner_fragment.xml:
<FrameLayout 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">
<FrameLayout
android:id="#+id/inner_fragment_framelayout"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<android.support.design.widget.BottomNavigationView
android:id="#+id/inner_fragment_bottom_navigation_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
app:menu="#menu/inner_fragment"
app:itemBackground="#drawable/bg_bottom_navigation"
app:itemIconTint="#color/ic_bottom_navigation"
app:itemTextColor="#color/ic_bottom_navigation"/>
</FrameLayout>
A simple solution is to just add an offset listener to appbarlayout. Works perfectly for me.
So something like this:
((AppBarLayout)toolbar.getParent()).addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
#Override
public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
mNavigationBar.setTranslationY(verticalOffset*-1);
}
});
This release of BottomNavigationView is missing scrolling behavior to work out of the box as specified in the guidelines.
I wrote an article on what's missing and how you can fix it. This includes implementing scrolling behavior of the BottomNavigationView in CoordinatorLayout.
My solution was to replace the FrameLayout with a NestedCoordinatorLayout from here https://stackoverflow.com/a/37660246/2233621 and then add the BottomNavigationBehavior from Nikola's blog post https://medium.com/#nullthemall/bottomnavigationview-missing-pearls-eaa950f9ad4e#.p1i01wwui that way your bottom navigation behaviour can listen for nested scrolling of the fragment inside the NestedCoordinatorLayout
I believe you could use another view that implements NestedScrollParent + NestedScrollChild for the same behaviour.
Related
I am making my TabLayout animated by using android:animateLayoutChanges="true" in AppBarLayout. But when I set TabLayout.setVisibility(View.GONE), container for my fragment goes up to ActionBar instantly for a few milliseconds. And then it returns to the end of TabLayout and goes up with it to the ActionBar. I explained this on following gif.
The buttons Theory and Practice are behind the TabLayout for some reason but when hiding TabLayout animation starts FrameContainer that holds my view sticks to the bottom of TabLayout.
I have recorded a video that demostrates this behavior. Dropbox video player skip some frames and animation seems nice. Thats why, to notice the bug, you can load video on computer and watch 5 and 11 second in high quality. Video
My LayoutXML:
<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:orientation="vertical">
<SurfaceView
android:layout_width="0px"
android:layout_height="0px"/>
<android.support.design.widget.AppBarLayout
android:id="#+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:animateLayoutChanges="true">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
android:minHeight="?attr/actionBarSize"
app:layout_scrollFlags="scroll|enterAlways"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light"
app:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"/>
<android.support.design.widget.TabLayout
android:id="#+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"
android:visibility="gone"
app:tabGravity="fill"
app:tabIndicatorColor="#android:color/white"
app:tabMode="fixed"/>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.DrawerLayout
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<!--
This FrameLayout holds my fragments.
-->
<FrameLayout
android:id="#+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/outer_background">
<ProgressBar
android:id="#+id/main_load_progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:indeterminate="true"/>
</FrameLayout>
<include
android:id="#+id/left_drawer_full"
layout="#layout/navigation_drawer"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"/>
</android.support.v4.widget.DrawerLayout>
</android.support.design.widget.CoordinatorLayout>
In addition I am using 23.2.1 support libraries.
How can I fix this blinks and jumps?
Try adding android:animateLayoutChanges="true" to your view with
app:layout_behavior="#string/appbar_scrolling_view_behavior
so that would be your DrawerLayout. Then enable Transition Type LayoutTransition.CHANGING on it like so:
ViewGroup layout = (ViewGroup) findViewById(R.id. drawer_layout);
LayoutTransition layoutTransition = layout.getLayoutTransition();
layoutTransition.enableTransitionType(LayoutTransition.CHANGING);
related: https://stackoverflow.com/a/22573099/1363742
I wasted all day to investigate this problem.
And I have found one possible solution for this problem.
Now i change visibility by this code
mTabLayout.postDelayed(new Runnable() {
#Override
public void run() {
switch (newMode) {
case MODE_CONTENTS:
mTabLayout.setVisibility(mContents.isTheoryAvailable() ? View.VISIBLE : View.GONE);
break;
default:
findViewById(R.id.content_frame).setVisibility(View.INVISIBLE);
mTabLayout.setVisibility(View.GONE);
findViewById(R.id.content_frame).setVisibility(View.VISIBLE);
}
}
}, 200);
It works well and views are not blinking now. But on old androids the bug is still presents.
Screenshot 1 and
Screenshot 2 of my app
The problem is basically this: The PagerTitleStrip and the RecyclerView go below my Toolbar even though I have set layout_behaviour to my ViewPager.
More detail:
I have a main activity that uses the layout below and then from it I launch fragments. Before trying the CoordinatorLayout + ViewPager and all of the other fancy stuff I just had a FrameLayout in which I displayed my fragments. However, I decided that I want to use
app:layout_scrollFlags="scroll|enterAlways"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
so that my Toolbar disappears when I scroll the recyclerview. I found online that FrameLayout had no behaviour in it to allow me to fix the position of the recyclerView going under the Toolbar and that's why I changed to ViewPager + CoordinatorLayout to manage my fragments.
However, that introduced a few problems. What I want to achieve is - A toolbar with a PagerTitleStrip attached to it, when I scroll the toolbar disappears leaving the PagerTitleStrip visible ideally, maybe it hides as well I don't care that much about that. But I want my Navigation Drawer to keep working and it doesn't. It's like it doesn't exist.
Now, this first layout actually has all of the above features working, but the problem is the strip is below the toolbar and it's not visible unless the Toolbar hides when I scroll. Drawer works. Recycler view items are partially hidden below the Toolbar unfortunately - they don't start scrolling from the right point of the screen even though I have that set - appbar_scrolling_view_behavior
Layout m_drawerlayout.xml for my main activity to inflate:
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/coordinatorLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.widget.DrawerLayout
android:id="#+id/drawer"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.view.ViewPager
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<android.support.v4.view.PagerTitleStrip
android:id="#+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="6dp"
android:paddingBottom="6dp"
android:layout_gravity="top"
android:textSize="15sp"
android:textColor="#color/tealfifty"
android:background="#color/teal">
</android.support.v4.view.PagerTitleStrip>
</android.support.v4.view.ViewPager>
<ListView
android:id="#+id/drawer_list"
android:background="#color/tealDark"
android:cacheColorHint="#android:color/transparent"
android:choiceMode="singleChoice"
android:divider="#drawable/list_divider"
android:dividerHeight="1dp"
android:layout_width="280dp"
android:layout_height="match_parent"
android:layout_gravity="start"/>
</android.support.v4.widget.DrawerLayout>
<android.support.design.widget.AppBarLayout
android:id="#+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<include layout="#layout/app_bar"/>
</android.support.design.widget.AppBarLayout>
</android.support.design.widget.CoordinatorLayout>
And this is the code for my app_bar.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/top_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="#color/teal"
app:theme="#style/ToolbarTheme"
app:popupTheme="#style/Green.Overlay.LightPopup"
app:layout_scrollFlags="scroll|enterAlways" >
<Spinner android:id="#+id/spinner"
android:layout_gravity="right"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawSelectorOnTop="true"
android:paddingRight="20dp"
/>
</android.support.v7.widget.Toolbar>
I tried moving elements around, in and out of other components but no success. For example, it seems logical that to make the PagerTitleStrip attached to the Toolbar and share one behaviour I'd have to nest the PagerTitleStrip inside the AppBar layout but PagerTitleStrip has to be a direct child of ViewPager to work...Any suggestions guys about all this? I'm new to all these design functionalities and I researched a lot without success, there are similar topics here but not at all what I need. Seems there's almost nothing on the internet about things I'm trying to do above (there are a few) compared to other basic topics.
If anyone is wondering why I'm using ViewPager when I have no tabs, it's because as I said, FrameLayout has no behaviour allowing me to use a disappearing Toolbar correctly and that's what I found is good to use. I also saw NestedScrollView could be used but I haven't used it ever so... I now want to possibly use the ViewPagerTitle which I guess limits me to ViewPager for the Fragments.
The problem is in the:
<android.support.design.widget.CoordinatorLayout
<android.support.v4.widget.DrawerLayout
Which the DrawerLayout should be the root layout.
Please see: http://developer.android.com/training/implementing-navigation/nav-drawer.html#DrawerLayout
To add a navigation drawer, declare your user interface with a
DrawerLayout object as the root view of your layout. Inside the
DrawerLayout, add one view that contains the main content for the
screen (your primary layout when the drawer is hidden) and another
view that contains the contents of the navigation drawer.
Also, it is not recommended to use ListView instead of NavigationView.
And here is the doc suggested way to do(except that ListView:) ):
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- The main content view -->
<FrameLayout
android:id="#+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<!-- The navigation drawer -->
<ListView android:id="#+id/left_drawer"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:choiceMode="singleChoice"
android:divider="#android:color/transparent"
android:dividerHeight="0dp"
android:background="#111"/>
</android.support.v4.widget.DrawerLayout>
And also:
However, that introduced a few problems. What I want to achieve is - A
Toolbar with a PagerTitleStrip attached to it, when I scroll the
toolbar disappears leaving the PagerTitleStrip visible ideally, maybe
it hides as well I don't care that much about that. But I want my
Navigation Drawer to keep working and it doesn't.
Check my answer about this one:
https://stackoverflow.com/a/35241363/4409113
You just put your Toolbar inside CollapsingToolbarLayout like this:
<android.support.design.widget.CollapsingToolbarLayout
android:id="#+id/collapsingtoolbarly"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
app:contentScrim="?attr/colorPrimary"
app:layout_scrollFlags="scroll|snap">
<android.support.v7.widget.Toolbar
android:id="#+id/my_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:elevation="4dp"
android:theme="#style/ThemeOverlay.AppCompat.ActionBar"
app:layout_collapseMode="pin"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light" />
<ImageView
android:layout_width="match_parent"
android:layout_height="190dp"
android:minHeight="190dp"
android:scaleType="fitXY"
android:src="#drawable/header"
app:layout_collapseMode="parallax" />
</android.support.design.widget.CollapsingToolbarLayout>
It should collapsed and the Toolbar will be hided after that.And if you want to keep that PagerTitleStrip(Recommended to use TabLayout Nowadays), just put it below the CollapsingToolbarLayout and above the </android.support.design.widget.AppBarLayout> like this:
</android.support.design.widget.CollapsingToolbarLayout>
<android.support.design.widget.TabLayout
android:id="#+id/tabLayout"
android:layout_width="match_parent"
android:layout_height="?actionBarSize"
android:background="?attr/colorPrimary" />
</android.support.design.widget.AppBarLayout>
That's pretty much it, Goodluck then.
In my application I have an issue where I want to have high level navigational control from a navigation drawer, and page level control within a TabLayout within a fragment. This however causes issues with the shadow rendering from the AppBar onto the fragment.
Here's the basics of what my layouts and code does. At the root I have this simple layout:
<?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"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" android:fitsSystemWindows="true"
tools:context=".MainAppActivity">
<android.support.design.widget.AppBarLayout android:layout_height="wrap_content"
android:layout_width="match_parent" android:theme="#style/AppTheme.AppBarOverlay">
<android.support.v7.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" />
</android.support.design.widget.AppBarLayout>
<include layout="#layout/content_main" />
</android.support.design.widget.CoordinatorLayout>
When my navigation drawer is selected I inflate the fragment into "content_main"
this.getSupportFragmentManager()
.beginTransaction()
.addToBackStack(tag)
.replace(R.id.content_main_layout, fragment, tag)
.commit();
The fragment being put into content_main contains a layout with my TabView and a view pager:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/fragment_github_issues"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<android.support.design.widget.TabLayout
android:id="#+id/github_issues_tab_layout"
android:layout_height="?attr/actionBarSize"
android:layout_width="match_parent"
android:layout_gravity="top"
android:background="?attr/colorPrimary"
android:theme="#style/AppTheme.AppBarOverlay"/>
<android.support.v4.view.ViewPager
android:id="#+id/github_issues_viewpager"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
</LinearLayout>
What's the a good best practice to fix the issue? Is including TabLayout to live within the top level AppBar and just disabling the view based on the page an acceptable implementation?
First you need to change the view hierarchy to something like this:
FrameLayout
-CoordinatorLayout -> content
-Toolbar
Fix Toolbar elevation to be exact with the AppBarLayout, too get rid of the shadow but keep the z-order of the Toolbar:
int appBarLayoutElevation = ViewCompat.getElevation(mAppBarLayout);
getActivity().getSupportActionBar().setElevation(appBarLayout);
Similar example I have worked in my blog post.
I have this layout:
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/coordinatorLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<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/toolbar"
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/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
</android.support.v7.widget.RecyclerView>
<android.support.design.widget.FloatingActionButton
android:id="#+id/fabButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|bottom"
android:src="#drawable/ic_favorite_outline_white_24dp"/>
</android.support.design.widget.CoordinatorLayout>
Setting #string/appbar_scrolling_view_behavior attribute shifts the RecyclerView by the height of the Toolbar.
But what if I need the first element of the RecyclerView to be aligned to the status bar.
I want the Toolbar to cover (be above) the first element.
In other words, I don't want any offset which #string/appbar_scrolling_view_behavior behaviour entails.
Could you please tell me how to do that?
I had the same problem and I just wrapped the AppbarLayout and the rest of my views (in your case the recyclerview) in a RelativeLayout and it works fine. I don't know if there are any downsides with that approach.
The offset is not by #string/appbar_scrolling_view_behavior behaviour it's due to AppBarLayout it pushes the content down.
I'm not sure if there is any other better solution. But I'd suggest to remove the AppBarLayout to have your content go under the Toolbar. Moreover you might be need the scrolling behaviour for that you can check the library below.
It's been used by lots of apps like Jair Music Player even WhatsApp too uses it.
Library:
Android Observable Scroll View
I need to create a GUI with a ListView and an ActionBar which will hide when scrolling down and when scrolling up it must reappear.
The following guides didn't help me:
https://mzgreen.github.io/2015/06/23/How-to-hideshow-Toolbar-when-list-is-scrolling%28part3%29/
https://github.com/ksoichiro/Android-ObservableScrollView
I need something like this:
If you would like to obtain a list with this behaviour, you should:
add the design support library with compile 'com.android.support:design:22.2.0'
Use a CoordinatorLayout with a Toolbar where you have to define app:layout_scrollFlags="scroll|enterAlways"
Use a RecyclerView instead of a ListView. As described here ListView and the GridView have the expected behavior with the CoordinatorLayout only with API>21. In this case you have to use setNestedScrollingEnabled(true);
The official blog post shows this case:
<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">
<! -- Your Scrollable View -->
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
...
app:layout_scrollFlags="scroll|enterAlways">
</android.support.design.widget.AppBarLayout>
</android.support.design.widget.CoordinatorLayout>
I would recommend using the new support design library by Google.
Include it in your dependecies:
compile 'com.android.support:design:22.2.0'
and then use the AppBarLayout together with NestedScrollView.
For your Toolbar define app:layout_scrollFlags="scroll|enterAlways", which says it will disappear as you scroll, and come back immediately if you scroll up (meaning you don't have to scroll all the way up).
<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"
android:background="?attr/colorPrimary"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light"
app:layout_scrollFlags="scroll|enterAlways" />
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="fill_vertical"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<FrameLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</android.support.v4.widget.NestedScrollView>
Use [CoordinatorLayout]:https://developer.android.com/reference/android/support/design/widget/CoordinatorLayout.html, which allow co-oridanation among child views. it's like, act(AppBarLayout->scrolling) on some view when there is a behaviour observed(ListView->scroll) in another view.
Make Listview nestedScrollingEnabled, works for >API 21
android:nestedScrollingEnabled="true"
Trigger layout behaviour to appbar scrolling.
android:nestedScrollingEnabled="true"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
Any layout(ToolBar/TabLayout/any), which is required to show-hide/scroll, place it inside AppBarLayout, and enabled scroll flag.
app:layout_scrollFlags="scroll|enterAlways"
you should use CoordinatorLayout for this task. It is part of the support design library. Here, in the CoordinatorLayout and the app bar section, you can find an example