DrawerLayout with Navigation Component doesn't get behind a translucent Status Bar - android

What I want to achieve is the Material Design DrawerLayout getting behind a translucent Status Bar, as such:
I am using the new Navigation Architecture Component, which means this is my current structure (I will make it simple since it can have a lot of useless code):
main.xml:
<FrameLayout
...
android:layout_width="match_parent"
android:layout_height="match_parent"
...
android:fitsSystemWindows="true" >
<fragment
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/main_nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
app:navGraph="#navigation/main_nav_graph"
app:defaultNavHost="true" />
</FrameLayout>
Then inside the Navigation Graph Fragment on main.xml I load the DrawerLayout itself:
fragment_main_nav.xml:
<androidx.drawerlayout.widget.DrawerLayout
...
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<!-- Layout to contain contents of main body of screen (drawer will slide over this) -->
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
...
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<!-- Container for contents of drawer - using NavigationView to make configuration easier -->
<com.google.android.material.navigation.NavigationView
android:id="#+id/drawer_navigation_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:menu="#menu/drawer_view"
app:headerLayout="#layout/drawer_nav_header"/>
</androidx.drawerlayout.widget.DrawerLayout>
And in my styles.xml I have my Theme as:
<style name="AppTheme" parent="WindowAppTheme">
<item name="colorPrimary">#color/colorPrimary</item>
<item name="colorPrimaryDark">#color/colorPrimaryDark</item>
<item name="colorAccent">#color/colorAccent</item>
</style>
<style name="WindowAppTheme" parent="Theme.MaterialComponents.Light.NoActionBar"></style>
And v21 styles.xml:
<style name="WindowAppTheme" parent="Theme.MaterialComponents.Light.NoActionBar">
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:statusBarColor">#android:color/transparent</item>
</style>
With this I can't get the `DrawerLayout to show it's top under the translucent Status Bar, this is what I get instead:
I tried several different ways, placing android:fitsSystemWindows=true and removing it from everywhere, but I can't get this to work! Or the Status Bar doesn't have a translucent color, or it's white.
What's the correct way to setup a DrawerLayout, under the Material Design specs, with Navigation Architecture Component?
EDIT:
I restructured the app as Ian's suggestion and now the DrawerLayout is showing into the Status Bar, but there's no scrim, no translucid bar over there on top of the DrawerLayout:

A DrawerLayout must be placed at the root of your hierarchy - the FrameLayout you are using only knows that it needs to pad everything in to fitsSystemWindows and won't allow your DrawerLayout to go into the status bar area.
Therefore your main.xml should be something similar to the navigation testapp:
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/main_drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/main_nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
app:navGraph="#navigation/main_nav_graph"
app:defaultNavHost="true"
/>
<android.support.design.widget.NavigationView
android:id="#+id/drawer_navigation_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:menu="#menu/drawer_view"
app:headerLayout="#layout/drawer_nav_header"/>
</android.support.v4.widget.DrawerLayout>
And your MainActivity should include code such as:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.main)
val navController = findNavController(R.id.main_nav_host_fragment)
// Change whether the drawer is enabled
// based on what destination you're on
val drawerLayout = findViewById<DrawerLayout>(R.id.main_drawer_layout)
navController.addOnNavigatedListener { _, destination ->
if (navController.graph.startDestination == destination.id) {
// We're at the root of your graph, so unlock the drawer
drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED,
GravityCompat.START)
} else {
// We're on any other destination so disable the drawer
drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED,
GravityCompat.START)
}
}
// Setup the NavigationView to navigate to the correct
// destination in the graph. Since we've locked the drawer
// on anything but the startDestination, we can guarantee
// that you're on that destination when these items are clicked
val navigationView = findViewById<NavigationView>(R.id.drawer_navigation_view)
navigationView.setupWithNavController(navController)
}
Since you're not using a Toolbar or any equivalent construct, your MainFragment would need to add its own button and set it up to open the drawer when clicked:
val navigationButton = ...
navigationButton.setOnClickListener {
val drawerlayout = requireActivity().findViewById<DrawerLayout>(
R.id.main_drawer_layout)
drawerLayout.openDrawer(GravityCompat.START)
}

Related

How to set up Navigation Component with Navigation Drawer in Android?

How do I set up navigation component with navigation drawer?
How do I use it in my app?
Can everything be done with one Activity?
How do I handle toolbar visibility with just one Activity and fragments which have a dynamic toolbar visibility. Also, there are fragments which I need to close the drawer and make it inaccessible.
This question is a self answered question and works more as a tutorial than a real-life QA.
How do I set up navigation component with navigation drawer?
How do I use it in my app?
The navigation drawer set up differs a little when it comes to Navigation component.
Note, if you create a new app with drawer navigation, the current tutorial is not needed. However I'm going to explain some things that might look strange around here and if you decide to add a drawer at a later stage of the app
First, you need to set up your activity_main.xml and MainActivity to be ready for the Navigation Architecture:
<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout 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/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:openDrawer="start">
<include
layout="#layout/app_bar_main"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.google.android.material.navigation.NavigationView
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="#layout/nav_header_main"
app:menu="#menu/activity_main_drawer" />
</androidx.drawerlayout.widget.DrawerLayout>
where app_bar_main is just:
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android: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>
<include layout="#layout/content_main" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
And the content_main is where your fragments are going to be held:
<?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"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:showIn="#layout/app_bar_main">
<fragment
android:id="#+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="#navigation/mobile_navigation" />
</androidx.constraintlayout.widget.ConstraintLayout>
Things you should know: The activity mustn't have a AppBar set on AndroidManifest.xml:
android:theme="#style/AppTheme.NoActionBar"
If you notice app:menu="#menu/activity_main_drawer" in the NavigationView tag, the fragment names should be the same that they are inside the mobile_navigation.xml:
<group android:checkableBehavior="single">
<item
android:id="#+id/homeFragment"
android:icon="#drawable/ic_menu_camera"
android:title="#string/menu_home" />
<item
android:id="#+id/galleryFragment"
android:icon="#drawable/ic_menu_gallery"
android:title="#string/menu_gallery" />
<item
android:id="#+id/slideshowFragment"
android:icon="#drawable/ic_menu_slideshow"
android:title="#string/menu_slideshow" />
<item
android:id="#+id/toolsFragment"
android:icon="#drawable/ic_menu_manage"
android:title="#string/menu_tools" />
</group>
<item android:title="Communicate">
<menu>
<item
android:id="#+id/shareFragment"
android:icon="#drawable/ic_menu_share"
android:title="#string/menu_share" />
<item
android:id="#+id/sendFragment"
android:icon="#drawable/ic_menu_send"
android:title="#string/menu_send" />
</menu>
</item>
</menu>
This way, with what is going to be explained below there will be no need to call for onCreateOptionsMenu to detect the clicks. Android team has already solved that for us. Follow below.
Until now, this doesn't differ too much from the usual drawer set up we actually do. But, there are some configurations we would need to do in the logic part of the app. So let's open MainActivity.kt. First you will need these:
private var appBarConfiguration: AppBarConfiguration? = null
private var drawerLayout: DrawerLayout? = null
private var toolbar: Toolbar? = null
private var navController: NavController? = null
After that in your onCreate method:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
toolbar = findViewById(R.id.toolbar)
setSupportActionBar(toolbar) //set the toolbar
drawerLayout = findViewById(R.id.drawer_layout)
val navView: NavigationView = findViewById(R.id.nav_view)
navController = findNavController(R.id.nav_host_fragment)
appBarConfiguration = AppBarConfiguration(
setOf(
R.id.homeFragment,
R.id.galleryFragment,
R.id.slideShowFragment,
R.id.toolsFragment,
R.id.shareFragment,
R.id.sendFragment,
R.id.loginFragment,
R.id.phoneConfirmationFragment
), drawerLayout
)
setupActionBarWithNavController(navController!!, appBarConfiguration!!) //the most important part
navView.setupWithNavController(navController!!) //the second most important part
//other things unrelated
}
Let's see what's going on here:
First you would need a reference to the navController. The AppBarConfiguration is just a class which holds the fragments that are going to be opened as top level destinations. Which means that the fragment which is going to be opened after them would release the current one from the fragment back stack. It's important to tell to the AppBarConfiguration that we have a drawer also (passed as a parameter in the constructor).
Down below you would have a method called onSupportNavigateUp():
override fun onSupportNavigateUp(): Boolean {
val navController = findNavController(R.id.nav_host_fragment)
return navController.navigateUp(appBarConfiguration!!) || super.onSupportNavigateUp()
}
This method has to do with the up back button. But you won't need it too much if you have drawer navigation. This really comes in handy when you have a lot of fragments added on the backstack (or at least two).
Can everything be done with one Activity?
Yes, definitely! but still it requires a little bit more work when it comes to conditional navigation. Like when you want to show fragments which are not part of your drawer app. But still Google has done a huge progress with it. You can refer to conditional navigation here.
How do I handle toolbar visibility with just one Activity and
fragments which have a dynamic toolbar visibility. Also, there are
fragments which I need to close the drawer and make it inaccessible.
You can use addOnDestinationChangedListener from the navController:
navController.addOnDestinationChangedListener { _, destination, _ ->
when (destination.id) {
R.id.loginFragment, R.id.registerFragment, R.id.phoneConfirmationFragment -> {
toolbar?.visibility = View.GONE
drawerLayout?.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED)
}
else -> {
toolbar?.visibility = View.VISIBLE
drawerLayout?.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED)
}
}
}
Now you have a drawer and navigation component on your app.

Android drawer navigation dark mode with transparent status bar

I use navigation drawer in my app and I try to implement dark theme. When the app doesn't cover the whole screen and the status bar isn't transparent the navigationView is automatically colored to dark. But when the app covers the whole screen and the status bar is transparent the navigationView stays white. How can I force the navigationView to be dark even when the app covers the whole screen and status bar is transparent?
I don't explicitily set the background color or the text color, it uses the default values.
The layout code looks like this:
<androidx.drawerlayout.widget.DrawerLayout 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"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:id="#+id/drawer_layout">
<!-- Some other views wrapped in RelativeLayout -->
<com.google.android.material.navigation.NavigationView
android:id="#+id/mainnav"
android:layout_width="wrap_content"
android:layout_height="match_parent"
app:menu="#menu/mainmenu"
android:layout_gravity="start"
app:headerLayout="#layout/mainmenu_header"
android:fitsSystemWindows="false"
app:insetForeground="#null">
<include android:id="#+id/mainmenuheader"
layout="#layout/mainmenu_header"/>
</com.google.android.material.navigation.NavigationView>
</androidx.drawerlayout.widget.DrawerLayout>
The style that the activity uses to make it fullscreen with transparent status bar looks like this:
<style name="Theme.AppCompat.Light.NoActionBar.FullScreen" parent="#style/Theme.AppCompat.Light.NoActionBar">
<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowTranslucentNavigation">true</item>
</style>
And finally in the manifest for the activity a apply the theme and set the fitsSystemWindows to true:
<activity
android:name=".map.MapActivity"
android:screenOrientation="portrait"
android:configChanges="uiMode"
android:fitsSystemWindows="true"
android:theme="#style/Theme.AppCompat.Light.NoActionBar.FullScreen" />

How to remove back button from toolbar when using bottom menu bar with navigation architecture components

I have an application which has a bottom menu bar which users can use to switch between 4 home page tabs. It's working fine like below.
The only problem I'm having is it showing back button when I switch between different fragment. Since all these fragments are at the same level I do not want it to behave like that.
This is my implementation.
MainNavigationActivity
class MainNavigationActivity : AppCompatActivity() {
private lateinit var navigationController: NavController
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
initialization()
}
private fun initialization(){
navigationController = Navigation.findNavController(this, R.id.hostFragment)
setSupportActionBar(toolbar)
NavigationUI.setupWithNavController(bottomNavigationBar,navigationController)
NavigationUI.setupActionBarWithNavController(this,navigationController)
}
override fun onBackPressed() {
onSupportNavigateUp()
}
MainNavigationActivity Layout
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".activities.MainNavigationActivity">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:background="#color/colorPrimary"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light"
app:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"/>
<fragment
android:id="#+id/hostFragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#id/toolbar"
android:layout_above="#id/bottomNavigationBar"
app:defaultNavHost="true"
app:navGraph="#navigation/main_navigation_graph" />
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/bottomNavigationBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="#android:color/white"
app:menu="#menu/bottom_navigation_menu"
app:labelVisibilityMode="labeled"/>
</RelativeLayout>
bottom_navigation_menu.xml
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="#+id/navigation_home"
android:state_checked="true"
android:color="#color/colorPrimary"
android:title="#string/navigation_home"
android:icon="#drawable/ic_bottom_bar_menu_home"/>
<item
android:id="#+id/navigation_offers"
android:state_checked="false"
android:color="#color/gray"
android:title="#string/navigation_offers"
android:icon="#drawable/ic_bottom_bar_menu_offers"/>
<item
android:id="#+id/navigation_my_bookings"
android:state_checked="false"
android:color="#color/gray"
android:title="#string/navigation_my_bookings"
android:icon="#drawable/ic_bottom_bar_menu_bookings"/>
<item
android:id="#+id/navigation_my_account"
android:state_checked="false"
android:color="#color/gray"
android:title="#string/navigation_my_account"
android:icon="#drawable/ic_bottom_bar_menu_account"/>
</menu>
The Ids are given to the fragments in the navigation graph and the ids in the menu.xml are the same. that's how it identifies the correct fragment and switch to that fragment correctly.
How can I remove this back button on the toolbar in home screen level?
As per the NavigationUI documentation:
By default, the Navigation button is hidden when a user is at a top-level destination of a navigation graph and appears as an Up button in any other destination.
If you want to customize which destinations are considered top-level destinations, you can instead pass a set of destination IDs to the constructor, as shown below:
val appBarConfiguration = AppBarConfiguration(setOf(
R.id.navigation_home, R.id.navigation_offers,
R.id.navigation_my_bookings, R.id.navigation_my_account))
(Note that this constructor requires the navigation-ui-ktx artifact - the alternative is to use the AppBarConfiguration.Builder)
You can also use the extension function for AppBarConfiguration that takes the bottom navigation menu as its argument, just to make things a bit easier. Check here
It will set all the fragments in your bottom navigation bar as the top-level destinations.
It is as simple as this:
val appBarConfiguration = AppBarConfiguration(bottomNavigationBar.menu)
setupActionBarWithNavController(navigationController, appBarConfiguration)
And also as suggested by #ianhanniballake, you need to have navigation-ui-ktx for this to work.
//hide back arrow in toolbar inside fragment while using NavigationComponent
((AppCompatActivity)getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(false);

Translucent/Transparent status bar + CoordinatorLayout + Toolbar + Fragment

I have following setup:
I'm using AppCompat
MainActivity, that holds a fragment and has a toolbar, that's hiding when scrolling down
Fragment with RecyclerView
all views that should fit the screen have the according android:fitsSystemWindows="true" in the xml layout
The problem is, I can't get the statusbar transparent in this case. What I do is following:
Create the activity and call setContent
Then I try to adjust the activity to programmatically get a translucent toolbar like following:
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public void themeNavAndStatusBar(Activity activity)
{
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP)
return;
Window w = activity.getWindow();
w.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
w.setFlags(
WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION,
WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
w.setFlags(
WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS,
WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
w.setNavigationBarColor(activity.getResources().getColor(android.R.color.transparent));
w.setStatusBarColor(activity.getResources().getColor(android.R.color.transparent));
}
Replace the placeholder in the activity (#+id/frame_container) with the fragment
The statusbar is solid colored in this case, and the views are not drawn underneath it... Why?
What I want
I want a toolbar, that is scrolled of the screen and hiding completely while the content underneath this toolbar should fitScreen and be drawn behind the transparent nav bar.
Layouts
Here's my main activity:
<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/clMain"
android:fitsSystemWindows="true"
android:background="?attr/main_background_color"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:id="#+id/appBarLayout"
android:fitsSystemWindows="true"
android:background="#null"
app:elevation="0dp"
app:contentInsetLeft="0dp"
app:contentInsetStart="0dp"
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"
android:elevation="4dp"
android:theme="?actionBarThemeStyle"
app:popupTheme="?actionBarPopupThemeStyle"
app:layout_scrollFlags="scroll|enterAlways">
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/ivToolbarDataSource"
android:layout_gravity="center_vertical"
android:layout_marginRight="2dp"
android:layout_width="24dp"
android:layout_height="24dp" />
<TextView
android:id="#+id/tvToolbarTitle"
style="#style/TextAppearance.AppCompat.Widget.ActionBar.Title"
android:theme="?actionBarThemeStyle"
android:layout_gravity="center_vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<TextView
android:id="#+id/tvToolbarSubTitle"
style="#style/TextAppearance.AppCompat.Widget.ActionBar.Subtitle"
android:theme="?actionBarThemeStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</android.support.v7.widget.Toolbar>
<!-- BUG: http://stackoverflow.com/questions/30541409/coordinatorlayoutappbarlayout-does-not-draw-toolbar-properly -->
<View
android:layout_width="fill_parent"
android:layout_height="1dp"/>
</android.support.design.widget.AppBarLayout>
<FrameLayout
android:id="#+id/frame_container"
android:fitsSystemWindows="true"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
<android.support.design.widget.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|right"
android:layout_margin="32dp"
android:src="#drawable/ic_local_offer_white_24dp"
app:backgroundTint="?attr/colorPrimary"
app:borderWidth="0dp"
app:fabSize="normal"
app:rippleColor="?attr/colorPrimaryDark"
app:layout_anchorGravity="bottom|right|end"
app:layout_behavior="com.test.classes.ScrollAwareFABBehavior"/>
</android.support.design.widget.CoordinatorLayout>
And here is my fragment, that will be placed in the main activity:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:fitsSystemWindows="true"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.widget.SwipeRefreshLayout
android:id="#+id/srlImages"
android:fitsSystemWindows="true"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="#+id/rvImages"
android:fitsSystemWindows="true"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</android.support.v4.widget.SwipeRefreshLayout>
<TextView
android:id="#+id/tvEmpty"
android:gravity="center"
android:layout_centerInParent="true"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</RelativeLayout>
EDIT - Screenshots
I use a light/dark base theme and theme everything by hand (because the user can select any color as primary/accent color), so don't mind that the toolbar is white (it's the default's theme background color and primary color). I added a black border as well so that you see where the activity ends...
First Screenshot: Shows the toolbar, nothing is scrolled
Second Screenshot: I just started scrolling => the toolbar now should scroll away
Third Screenshot: the main content should now scroll underneath the nav bar...
In the end, I'll of course make the toolbar and navbar semi transparent for a better visual effect...
tl;dr Set android:fitsSystemWindows="false" at least to the root CoordinatorLayout and to the inner fragment container, #frame_container.
This might not be the final solution (i.e. there might be other fitsSystemWindows to change) so tell me if you have any problems.
why
When it comes to status bar, I think of fitsSystemWindows like so:
fitsSystemWindows="false" : draws the view normally, under the status bar because of the window flags you have set.
fitsSystemWindows="true" : draws the view normally, under the status bar because of the window flags you have set, but adds a top padding so that content is drawn below the status bar and they don't overlap.
In fact, in my opinion, the white you see is not the status bar color, but rather your CoordinatorLayout background. That is due to fitsSystemWindows="true" on the coordinator: it draws the background to the whole window, but adds top padding to the content so inner views are not covered by status bar.
This is not what you want. Your inner content must be covered by the status bar, and so you have to set fitsSystemWindows="false" to the coordinator (so it won't apply top padding) and probably to the content itself.
Once you get how it works, it is easy to debug and achieve the effect you are looking for. Actually, it is not. Years pass, but I still spend hours trying to figure out the right fitsSystemWindows combination, because most Views (in the support libraries at least) override the default behavior that I stated above, in ways that are mostly not intuitive. See this post for a small guide on how to use it.
Edit your styles.xml (v21) , add the following style
<style name="AppTheme.Home" parent="AppTheme.Base">
<!-- Customize your theme here. -->
<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:windowTranslucentNavigation">true</item>
</style>
You can change parent theme as per your liking, but now declare this theme in your AndroidManifest.xml file for a particular activity like this :
<activity
android:theme="#style/AppTheme.Home"
android:name=".HomeActivity"
android:launchMode="singleTop"
android:screenOrientation="portrait" />
This will let your content visible under the transparent actionbar.
Now use the following to align your toolbar below the StatusBar properly, call this in your oncreate:
toolbar.setPadding(0, getStatusBarHeight(), 0, 0);
Get statusbar height using following :
public int getStatusBarHeight() {
int result = 0;
int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
result = getResources().getDimensionPixelSize(resourceId);
}
return result;
}
Remove the following from your coordinator layout tags :
android:fitsSystemWindows="true"
Now in order to collapse your toolbar or hide it you may refer to this tutorial
Make sure you are using following version of design support library, as it is bug free :
compile 'com.android.support:design:23.1.0'
After reading your descriptions about your question, I thought styles of Google Photos matches your requirement.
OK, there are just some tips for your question. After my test, it works.
If you want to show content behind status bar, you need add <item name="android:windowTranslucentStatus">true</item> into your
style when Android version level is larger than 19(namely KitKat)
If you want to show content behind navigation bar, you need add
<item name="android:windowTranslucentNavigation">true</item> into your
style when Android version level is larger than 19(namely KitKat)
If you want to hide Toolbar smoothly when content is scrolled up
and to show Toolbar smoothly when content is scrolled down, you
need to add app:layout_collapseMode="parallax" into your
Toolbar's attributes based on your current codes.Of course, you
need coordinate Toolbar with CollapsingToolbarLayout
CoordinatorLayout and AppBarLayout.
as some users said, by setting android:fitsSystemWindows="false", the layout overlapped below statusbar.
I solved it by setting android:fitsSystemWindows="true" and in CoordinatorLayout tag setting app:statusBarBackground="#android:color/transparent".
For me, the reason was not that it did not work per se, but that I use the material drawer library from Mike Penz and this library does use fullscreen + offset + custom background behind the toolbar so I had to solve the problem respecting that special setup...
I'll reward the points to the in my opinion most informative answer though...
I had the same issue and my solution was add android:fitsSystemWindows="true" to the DrawerLayout
<android.support.v4.widget.DrawerLayout 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/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
....
</android.support.v4.widget.DrawerLayout>
I had relevant issues depend on android:fitsSystemWindows setting.
Once false:
Snacks was drawn under the Navigation bar
Once true:
Status bar had none transparent background
Solution was really simple...
Just to add android:layout_marginBottom="48dp". to CoordinatorLayout like that:
just to add <android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:map="http://schemas.android.com/apk/res-auto"
tools:context=".MapsActivity"
android:id="#+id/coordinatorLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="false"
android:layout_marginBottom="48dp">
Theoretically Navigation bar should have fixed size "48dp", but in future releases potentially it may change (like Status bar got slimmer by 1dp in Marshmallow), so I wouldn't rely on fixed size.
Better additionally get it and apply on run time.
If You are using Google Map like me You may want to know ActionBar/Toolbar size and the navigation bar in run time:
in onCreate use this code:
final TypedArray styledAttributes = MapsActivity.this.getTheme().obtainStyledAttributes(
new int[]{android.R.attr.actionBarSize});
mToolbarHeight = (int) styledAttributes.getDimension(0, 0);
styledAttributes.recycle();
// translucent bars code. Will not fire below Lollipop
// Ask NavigationBar Height
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.coordinatorLayout),
new OnApplyWindowInsetsListener() { // setContentView() must be fired already
#Override
public WindowInsetsCompat onApplyWindowInsets(View v, WindowInsetsCompat insets) {
statusBar = insets.getSystemWindowInsetTop(); // You may also need this value
mNavBarHeight = insets.getSystemWindowInsetBottom();
if (mMap != null)
mMap.setPadding(0, mToolbarHeight, 0, mNavBarHeight);
// else will be set in onMapReady()
SharedPreferences.Editor editor = mSharedPref.edit();
editor
.putInt(NAVBAR_HEIGHT_KEY, mNavBarHeight)
.commit(); // Save the results in flash memory and run the code just once on app first run instead of doing it every run
return insets;
}
}
);
And what's important. If You got some additional layers like drawer etc put them encapsulating the CoordinatorLayout inside rather than outside as otherwise it will make other views inside shorter by the marginBottom
Here's what I did to have the toolbar have the same color as the status bar, by getting the status bar transparent:
build.gradle
...
implementation 'androidx.core:core-ktx:1.2.0'
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'com.google.android.material:material:1.1.0'
**ScrollingActivity.kt**
```kt
class ScrollingActivity : AppCompatActivity(R.layout.activity_scrolling) {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setSupportActionBar(toolbar)
}
}
activity_scrolling.xml
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true"
tools:context=".ScrollingActivity">
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/app_bar" android:layout_width="match_parent" android:layout_height="wrap_content"
android:background="#f00" android:fitsSystemWindows="true" android:theme="#style/AppTheme.AppBarOverlay">
<com.google.android.material.appbar.MaterialToolbar
android:id="#+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize"
app:popupTheme="#style/AppTheme.PopupOverlay" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent" android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<TextView
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:layout_margin="#dimen/text_margin" android:text="#string/large_text" />
</androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
styles.xml
<resources>
<style name="AppTheme" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<item name="colorPrimary">#color/colorPrimary</item>
<item name="colorPrimaryDark">#color/colorPrimaryDark</item>
<item name="colorAccent">#color/colorAccent</item>
</style>
<style name="AppTheme.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
<item name="android:statusBarColor">#android:color/transparent</item>
</style>
<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
</resources>
manifest
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.lb.myapplication">
<application
android:allowBackup="true" android:icon="#mipmap/ic_launcher" android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="#style/AppTheme">
<activity
android:name=".ScrollingActivity" android:label="#string/app_name"
android:theme="#style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
You should add the following code to your theme, this code will make the status bar transparent:
<item name="android:windowTranslucentStatus" tools:targetApi="kitkat">true</item>
Additionally, add scroll behavior to your top app bar. The following example shows the top app bar disappearing upon scrolling up, and appearing upon scrolling down:
<androidx.coordinatorlayout.widget.CoordinatorLayout
...>
<com.google.android.material.appbar.AppBarLayout
...>
<com.google.android.material.appbar.MaterialToolbar
...
app:layout_scrollFlags="scroll|enterAlways|snap"
/>
</com.google.android.material.appbar.AppBarLayout>
...
</androidx.coordinatorlayout.widget.CoordinatorLayout>
First add this code to AppBarLayout:
app:liftOnScroll="true"
Then update your "app:layout_scrollFlags" in your toolbar:
app:layout_scrollFlags="scroll|enterAlways|snap"
This will work, I am pretty sure.

Android NavigationView (material support lib) doesn't interact with the status bar properly

I'm following the example from here to integrate the new Material Design Support library's NavigationView into my app.
My general layout looks like this:
activity.xml
<android.support.v4.widget.DrawerLayout
android:fitsSystemWindows="true">
<!-- main content -->
<android.support.design.widget.NavigationView
.. />
</android.support.v4.widget.DrawerLayout>
themes.xml
<style name="MyTheme" extends "Theme.AppCompat.Light.NoActionBar">
<item name="android:statusBarColor">#android:color/transparent</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
</style>
MyActivity.java
onCreate(..) {
..
// This color can be different depending on some conditions.
DrawerLayout.setStatusBarBackground(color);
}
However, I keep getting a grey status bar, and the NavigationView does not draw under the status bar. I think the grey status bar is because I didn't define a custom colorPrimaryDark attr in the theme. However, I would assume DrawerLayout.setStatusBarBackground would override and set the status bar color. I can't find much documentation on the new NavigationView. Does anyone have any ideas?
Add your styles for API 21+ in values-v21/themes.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="MyTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:statusBarColor">#android:color/transparent</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
</style>
</resources>
In activity.xml, try setting android:fitsSystemWindows="true" on your NavigationView (in addition to the DrawerLayout).
For every one struggling with this, your layout file should be something like this:
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
...
<android.support.design.widget.NavigationView
android:id="#+id/nav_view"
android:layout_height="match_parent"
android:layout_width="wrap_content"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="#layout/drawer_header"
app:menu="#menu/menu_drawer"/>
</android.support.v4.widget.DrawerLayout>
You have to include
android:fitsSystemWindows="true"
in the DrawerLayout and in the NavigationView.
Sigh, I figured out my problem. There was some weird abstraction that we use to add a debug drawer on the right-hand side. As a result, the overall view hierarchy actually looks like this
<DrawerLayout id="debug">
<LinearLayout id="debug_drawer" />
<DrawerLayout id="nav_drawer" fitsSystemWindows="true">
<NavigationView .... />
</DrawerLayout>
</DrawerLayout>
So I was calling DrawerLayout.setStatusBarColor on the wrong drawer and setting fitsSystemWindows on the wrong drawer. As a result, the window never interacts with the status bar :(

Categories

Resources