NavigationView without gray border when using fitsSystemWindows - android

I created a new App with Android Studio 2.0 and I want to have my Navigation Drawer below the Toolbar. I know the Material Design specs say it should be above the Toolbar but my Drawer won't have that much entries and I want to see the neat icon animation provided by Google.
I maged to get what I want by placing the DrawerLayout within the top level CoordinatorLayout.
<?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="com.company.app.MainActivity">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
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>
<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"
tools:openDrawer="start">
<include layout="#layout/content_main" />
<android.support.design.widget.NavigationView
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:menu="#menu/activity_main_drawer" />
</android.support.v4.widget.DrawerLayout>
</android.support.design.widget.CoordinatorLayout>
I am using android:fitsSystemWindow="true" on the top level layout so I can tint the status bar. But when I do that, the Navigation Drawer does have a gray top border.
When I would be using it the way Google specified it (above the Toolbar) then the border would be fine but this way it just looks ugly. Is there any way to remove this?
I experimented with overriding NavigationView.onInsetsChanged(Rect rect) and was able to place the items at the top but the gray border remained.

I had a headache trying to figure this out also and managed to find this which describes how CoordinatorLayout passes fitsSystemWindows to its child. I definitely think this is a bug since NavigationView already has it set to false, but then I read this:
NavigationView takes care of the scrim protection of the status bar for you, ensuring that your NavigationView interacts with the status bar appropriately on API21+ devices.
from the Android Developers Blog. So I'm not sure what to think of it. I think it might be due to the fact that NavigationView was never intended to be used this way.
Nonetheless, here's a solution you can try that fixes the gray bar issue, but I haven't figured out if it might cause anymore problems. If so please post back.
In the activity_main.xml:
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
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_width="240dp"
android:layout_height="match_parent"
android:layout_marginTop="100dp"
android:fitsSystemWindows="false"/>
</android.support.design.widget.CoordinatorLayout>
In MainActivity class:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
if (navigationView != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
navigationView.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() {
#Override
public WindowInsets onApplyWindowInsets(View v, WindowInsets insets) {
return insets;
}
});
}
}
}
Should get you this:

Related

Grey bar appears on navigation drawer

I recently implemented a navigation drawer into the main screen of my app. For some reason a small grey (or transparent black) bar is being rendered on top of it.
Screenshot:
Layout code:
<android.support.design.widget.CoordinatorLayout
... >
<LinearLayout
... >
<android.support.design.widget.AppBarLayout
android:id="#+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="#dimen/appbar_padding_top"
android:theme="#style/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:layout_scrollFlags="scroll|enterAlways"
app:popupTheme="#style/PopupOverlay"/>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.DrawerLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/drawer_layout">
<fragment
... />
<android.support.design.widget.NavigationView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:id="#+id/navigation"
android:layout_gravity="start">
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/list_nav"/>
</android.support.design.widget.NavigationView>
</android.support.v4.widget.DrawerLayout>
</LinearLayout>
<android.support.design.widget.FloatingActionButton
... />
</android.support.design.widget.CoordinatorLayout>
The Java portion is just your generic list-filling stuff. Let me know if you need more code.
How can I remove this weird bar?
For me, it worked to add
app:insetForeground="#color/transparent"
to the NavigationView's XML definition.
NavigationView is a very specialized ViewGroup that builds its own internal structure from provided resources. It's not meant to be used as a regular ViewGroup. That is, it's not meant to have child Views added directly to it, either in layout XML, or in code.
This is not immediately apparent, though, since no fatal error will occur if you do add children to it manually. It is further muddled by the fact that Android Studio's recent Navigation Drawer templates use NavigationView as the default drawer View in the DrawerLayout, with no indication that it is not mandatory that the drawer be a NavigationView. A drawer can be virtually any kind of View or ViewGroup.
In this case, the shadow is apparently coming from something internal to the NavigationView. However, since it's not being used for any of its specialized features, the NavigationView can be removed completely, and the ListView can act as the drawer on its own.
Simply remove the <NavigationView> element, and any code associated with it. To setup the ListView as the drawer, set its layout_gravity attribute to start, and set its layout_width to an exact value; e.g., 240dp.
i add in my activity_main.xml line:
<com.google.android.material.navigation.NavigationView
...
app:insetForeground="#android:color/transparent" />
and it works fine!

How to achieve this layout on tablet?

I'm trying to create a good UI interface for tablet / large screen device.
The perfect solution would be the one running on GMail app (see screenshot below).
As far as I can understand, the layout is composed like this:
<?xml version="1.0" encoding="utf-8"?>
<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"
tools:openDrawer="start">
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android: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/activity_main_twopane" />
<android.support.design.widget.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="#dimen/fab_margin"
android:src="#drawable/ic_add" />
</android.support.design.widget.CoordinatorLayout>
<android.support.design.widget.NavigationView
android:id="#+id/navigation_drawer"
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" />
</android.support.v4.widget.DrawerLayout>
But if I adopt my solution, this will give me to 2 problems:
The FloatingActionButton on my code is on the bottom|end of the layout; in GMail app this is positioned only on the list layout (the one which contains e-mails);
The Toolbar on my code is only one (and I have a search action too), but it seems that on GMail app there are 2 of them: one as main with search option and the second one for details actions that are visible when you select an email.
Any advice that will lead me to to achieve the layout on screenshot?
Quick answer for your question 2 and 3:
In order to place the FAB in the desired place you have to add this tag on FloatingActionButton xml code: app:layout_anchor="#id/desired_view_id" and app:layout_anchorGravity="bottom|right|end";
In bottom toolbar you can define separate toolbar and style it.
See code below
// this is top toolbar
Toolbar toolbarTop = (Toolbar) findViewById(R.id.toolbar_top);
setSupportActionBar(toolbarTop);
// this is bottom one
Toolbar toolbarBottom = (Toolbar) findViewById(R.id.toolbar_bottom);
toolbarBottom.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
#Override
public boolean onMenuItemClick(MenuItem item) {
switch(item.getItemId()){
case R.id.action_settings:
// TODO
break;
// TODO: Other cases
}
return true;
}
});
// Inflate a menu to be displayed in the toolbar
toolbarBottom.inflateMenu(R.menu.menu_main);

Status bar overlaps toolbar on pre-lollipop but not on Lollipop / Marshmallow

This is the issue I am encountering
On pre-lollipop devices I have the following issue
On Lollipop and Marshmallow devices everything appears fine
I am trying to create the translucent status bar effect when opening the navigation drawer.
On Marshmallow and lollipop devices this is working fine.
Here is my code
activity_base.xml
<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/drawerLayout"
android:fitsSystemWindows="true"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout 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:background="#color/colorPrimary"
android:minHeight="?attr/actionBarSize"
android:theme="#style/ToolbarStyle"
app:theme="#style/ToolbarStyle" />
<FrameLayout
android:id="#+id/activity_content"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
<include layout="#layout/view_navigation_drawer_layout" />
</android.support.v4.widget.DrawerLayout>
view_navigation_drawer_layout.xml
<android.support.design.widget.NavigationView
android:id="#+id/navigation"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="#layout/nav_header" />
<ListView
android:id="#+id/lst_menu_items"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout>
</android.support.design.widget.NavigationView>
Note that I do the above because of the answer to this question NavigationView and custom Layout
Notice that both layouts have the android:fitsSystemWindows="true"
I thought maybe its because I include the layout so I tried copying the whole layout into the activity layout. Did not help
I also have this styles xml file in my values-v19 directory (for KitKat and above)
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="AppTheme" parent="MaterialDesign">
<item name="android:windowTranslucentStatus">true</item>
</style>
</resources>
I made a solution to this issue. However, my solution requires a BaseActivity that hijacks the layout as stated in this blog post http://mateoj.com/2015/06/21/adding-toolbar-and-navigation-drawer-all-activities-android/
here is my code
public class BaseActivity extends AppCompatActivity {
#Override
public void setContentView(int layoutResID) {
ViewGroup baseView = (ViewGroup) getLayoutInflater().inflate(R.layout.activity_base_with_drawer);
FrameLayout activityContainer = (FrameLayout) baseView.findViewById(R.id.activity_content);
getLayoutInflater().inflate(layoutResID, activityContainer, true);
super.setContentView(layoutResID);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
if (useToolbar()) { //Does the activity have a toolbar?
toolbar.setFitsSystemWindows(true); //toolbar will stretch underneath the status bar and because it naturally has a semi translucent background, it will assume a darker color of the toolbar which is usually the color primary.
setSupportActionBar(toolbar); //Set the toolbar
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
}
} else {
toolbar.setVisibility(View.GONE);
activityContainer.setFitsSystemWindows(true); //No toolbar so we set the container to have the fitsSystemWindow attribute to ensure contents do not overlay the system window such as status bar and navigation bar.
TypedValue outValue = new TypedValue();
boolean doesThemeHaveTranslucentWindow = getTheme().resolveAttribute(android.R.attr.windowIsTranslucent, outValue, true); //Check if the current activity theme has translucent window, this includes SearchActivity
if (!doesThemeHaveTranslucentWindow) { //If it does not then set the container background to colour primary to have the same effect as the toolbar being there and avoid a white status bar. We do not want to do this for translucent windows otherwise they would not be see through
activityContainer.setBackgroundColor(ContextCompat.getColor(this, R.color.colorPrimary));
}
}
}
And this is the layout
<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/drawerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout 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:background="#color/colorPrimary"
android:minHeight="?attr/actionBarSize"
android:theme="#style/ToolbarStyle"
app:theme="#style/ToolbarStyle" />
<FrameLayout
android:id="#+id/activity_content"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
<include layout="#layout/view_navigation_drawer_layout" />
</android.support.v4.widget.DrawerLayout>
FitsSystemWindows is no longer set in any of the XML layouts. This is done in the setContentViewMethod of the BaseActivity class.
If the activity does not have a toolbar, the activity container has the fitsSystemWindow attribute set to true otherwise, the toolbar has it applied.
If the activity does not have a toolbar, its container layout has a background colour set to the colour primary.
Why I do this is because when you set fitsSystemWindows on your toolbar it stretches underneath the status bar and because the status bar naturally has a semi translucent background, it will assume a darker color of the toolbar which is usually the color primary so we do this for the activity container to have the same effect.
Now there is a use-case I had in my app where I had an activity with a transparent window background which I check. If not true, the activity container has this colour set.
Not sure if its the best solution but its working well for me so far on Marshmallow, pre-lollipop and pre-KitKat too :P . Hope it helps out others.

"Hidden" Toolbar visible under status bar

Using the CoordinatorLayout to hide my toolbar when scrolling down.
The toolbar thinks it's hidden - But it's not.
Does anyone understand why this is happening?
Note: I have the status bar set to translucent to have proper material drawers. Making the status bar a solid color is not the solution I'm looking for - Unless of course that is how this was intended to be used.
I try to set statusbar color as the primarydark, then statusbar can not be transparent when drawer is opened otherwise toolbar comes out again.
After two days work, I found that if I remove the android:fitsSystemWindows="true" in my CoordinatorLayout, it solved.
<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"
tools:openDrawer="start">
<-- CoordinatorLayout is root of #layout/app_bar_home-->
<include
layout="#layout/app_bar_home"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<android.support.design.widget.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_home"
app:menu="#menu/activity_home_drawer" />
Not exactly sure what I was doing wrong but I was able to resolve this by following these examples:
https://github.com/chrisbanes/cheesesquare/blob/master/app/src/main/res/layout/activity_detail.xml
https://github.com/chrisbanes/cheesesquare/blob/f9eb39d29ea057b56e270263fa26f76e0bf3e77a/app/src/main/res/layout/include_list_viewpager.xml

Unable to setup navdrawer to go over toolbar in the new 5.0 SDK using appcompat-v7

Has anyone successfully got the navigation drawer to open over top of a toolbar that is being used with setSupportActionBar(toolbar)? I am using Theme.AppCompat.Light.NoActionBar.
If I make the Toolbar a child of the Drawerlayout in my xml, then the toolbar fills the entire screen no matter what height I set it to. The only other thing I could think of doing was wrapping my drawerlayout and toolbar in another parent layout and placing the toolbar outside of the navdrawer, but then the navdrawer opens up below the toolbar.
I was also not successful in getting the hamburger icon to transition to an arrow when using the navdrawer. I am using the new ActionBarDrawerToggle from the v7 compat library as well.
So I created a new test project targetting api21 only and used the following XML, and it also has the same problem where the toolbar fills the entire screen. The navdrawer DOES open over top of it in with this code.
Any help is greatly appreciated. Thanks
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<FrameLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<fragment android:id="#+id/navigation_drawer"
android:layout_width="#dimen/navigation_drawer_width"
android:layout_height="match_parent"
android:layout_gravity="start"
android:name="com.example.testnav.NavigationDrawerFragment"
tools:layout="#layout/fragment_navigation_drawer"/>
<Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/toolbar_actionbar"
android:layout_width="match_parent"
android:layout_height="?android:actionBarSize"
android:background="#43599a"/>
</android.support.v4.widget.DrawerLayout>
Here is my toolbar code from my activity:
final DrawerLayout mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
Toolbar mActionBarToolbar = (Toolbar) findViewById(R.id.toolbar_actionbar);
if (mActionBarToolbar != null) {
setActionBar(mActionBarToolbar);
}
if (mActionBarToolbar != null) {
mActionBarToolbar.setNavigationIcon(R.drawable.ic_drawer);
mActionBarToolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (mDrawerLayout.isDrawerOpen(Gravity.START)) {
mDrawerLayout.closeDrawer(Gravity.START);
} else {
mDrawerLayout.openDrawer(Gravity.START);
}
}
});
}
It can be a solution.
<!-- Main layout -->
<LinearLayout android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/headerbar"
android:orientation="vertical">
<!--Toolbar-->
<include layout="#layout/toolbar"/>
<include layout="#layout/main_container" />
</LinearLayout>
<!-- Nav drawer -->
<include layout="#layout/navdrawer" />
Another way is to put the toolbar inside the layout which you use in your main container.

Categories

Resources