0

What I want to achieve is the Material Design DrawerLayout getting behind a translucent Status Bar, as such:

DrawerLayout inside translucent status bar

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:

white status bar

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:

No scrim DrawerLayout

Michel Feinstein
  • 13,416
  • 16
  • 91
  • 173
  • Why is your `DrawerLayout` in `fragment_main_nav.xml` instead of at the `main.xml` level? – ianhanniballake Oct 23 '18 at 18:06
  • 2 reasons: 1- I can only navigate from inside the `NavHostFragment` itself, so inside `fragment_main_nav.xml` I can get the click on the `DrawerLayout` and navigate..... 2 - I don't want to allow the `DrawerLayout` to navigate to everywhere all the time, since my App only has one main screen and the others are like Settings and etc. So I want it to only show the `DrawerLayout` in the `fragment_main_nav.xml` and the when it navigates to a new destinaton, there won't be a `DrawerLayout` just a Up Navigation Arrow......maybe this all is feasible from `main.xml`, but it will be more complicated – Michel Feinstein Oct 23 '18 at 18:12
  • Also, `fragment_main_nav.xml` is behaving such as an `MainViewModel` that controls all other `ViewModels` under it, if I place it in `main.xml` I will need yet another `ViewModel` passing information all over the place, and I think its going to get even more complicated........or am I missing something and I am complicating everything myself? – Michel Feinstein Oct 23 '18 at 18:13
  • I would love to hear your comments on my decisions, your views on Android Architecture are way more experienced than mine... But even if my choices are all wrong, It should be working shouldn't it? – Michel Feinstein Oct 23 '18 at 18:30
  • @ianhanniballake I forgot the main reason why the `DrawerLayout` is inside `fragment_main_nav.xml`.... I don't have a traditional `Toolbar`, my app needs as much screen as it can get, so I have a menu button hovering on the side, so this menu button needs to be inside the `fragment_main_nav.xml`.....I could signal the press of this button to some other `ViewModel` to activate the `DrawerLayout` on `main.xml` but I wanted to avoid making it more complicated than it has to – Michel Feinstein Oct 23 '18 at 19:15
  • (I take back what I said on #1....It's possible to navigate from a reference to the `NavHostFragment` it's just not as simple, since you need to keep track where you are and where you want to go....whereas from inside the `NavHostFragment` you already know where you are) – Michel Feinstein Oct 23 '18 at 19:17

1 Answers1

1

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)
}
ianhanniballake
  • 191,609
  • 30
  • 470
  • 443
  • Man you are a life saver! I had no idea on the Lock mode! I will try this out, thanks! – Michel Feinstein Oct 23 '18 at 19:45
  • Ian, I made all the changes you suggested and indeed things are better structured....but the original problem persists, I can't get the `DrawerLayout` behind a translucid Status Bar. The only changes I did in my code was to add `android:fitsSystemWindows="true"` to the `DrawerLayout` and that's it. Same Theme, same structure. – Michel Feinstein Oct 23 '18 at 23:07
  • Can you add a screenshot of what you're seeing to the question? – ianhanniballake Oct 23 '18 at 23:28
  • Done, I posted it as an edit on the original question. – Michel Feinstein Oct 23 '18 at 23:36
  • That's not matching what I'm seeing, so perhaps there is something else wrong in your case. I'd try a more simple layout first (the DrawerLayout, NavigationView, and just a simple FrameLayout) and then add things from there. – ianhanniballake Oct 24 '18 at 13:34
  • I agree... I will create a new project from scratch and see how things go from there... If I bump into the same issue I will upload it to github with commits to where the change modified the expected behavior – Michel Feinstein Oct 24 '18 at 13:55
  • Ian, I revisited this issue and found the culprit, apparently the new Material Themes are broken. I opted for the new `"Theme.MaterialComponents.Light.NoActionBar"`, so this caused the problem. Switching to the old `"Theme.AppCompat.Light.NoActionBar"` did the trick. I will file a bug report with the Material Design team. – Michel Feinstein Nov 05 '18 at 18:45