Android Navigation Drawer and windowActionBarOverlay = true - android

I'm trying to implement the new Android Navigation Drawer in my application. I have created a BaseActivity.java that handles the Drawer setup and listeners, and I have two subactivities that extend this base class. On the second activity, I plan to use a different action bar style, using the following attrs:
<item name="android:windowActionBarOverlay">true</item>
<item name="android:background">#android:color/transparent</item>
to make the action bar transparent, and make content richer, as there is a picture header in my layout.
I've achieved just that, but now the problem is, that because the content is expanding to take advantage of the extra space of using the ActionBar as overlay, the Navigation Drawer itself is expanding too and it overlaps the ActionBar, creating a pretty awful looking layout:
What I'd like to have done, is the actual content (frame layout that will be populated with a fragment) to take up the extra space, but have the nav drawer still go underneath the action bar, similar to the Play Music App:
Any ideas on what I can do to make that happen?
EDIT So, as per Ahmad's assistance I set the marginTop on the ListView only. Here's the layout:
<!-- The navigation drawer -->
<ListView android:id="#+id/left_drawer"
android:layout_marginTop="?android:attr/actionBarSize"
<!-- This was added after seeing the crazy effect, but does nothing -->
android:layout_marginBottom="0dp"
android:layout_marginLeft="0dp"
android:layout_marginRight="0dp"
android:layout_width="240dp"
android:layout_height="fill_parent"
android:layout_gravity="start"
android:choiceMode="singleChoice"
android:background="?attr/listviewBackground"
/>
And now, it works great for the top side, but for some reason there's also a margin at the bottom of the view, which doesn't make any sense to me at all. Here's a screenshot.
Not sure what's causing it :(

And now, it works great for the top side, but for some reason there's also a margin at the bottom of the view, which doesn't make any sense to me at all. Here's a screenshot.
If you set your ListView gravity to start|bottom it solves your problem. No additional margin is added at the bottom. Looks like the DrawerLayout default gravity is start|center
<ListView
android:id="#+id/left_drawer"
android:layout_marginTop="?android:attr/actionBarSize"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start|bottom"/>

In case anyone is interested in another take to this question. Here's what happened.
I tried setting only the margin to the top of the list view like this:
android:layout_marginTop="?android:attr/actionBarSize"
But as mentioned on the edited question, that had a weird behaviour where there was also a margin on the bottom despite not being set on the layout resource file.
So, I was looking closely at the Play Music App and noticed that it's not actually a margin, but rather some padding, and additionally they are using a custom background that fills the space specified by the padding with a transparent color.
Here's what I did:
Set Padding at the top of the ListView, rather than margin:
android:paddingTop="?android:attr/actionBarSize"
As said before, it's important to not hard code the dimensions as they vary per device.
Create a custom drawable that has a top part transparent, and then rest of a solid color:
It looks somehow like this:
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item>
<shape android:shape="rectangle">
<solid android:color="#80000000" />
</shape>
</item>
<item android:top="#dimen/action_bar_default_height">
<shape
android:shape="rectangle">
<solid android:color="#color/light_gray" />
</shape>
</item>
Note that I tried to use ?android:attr/actionBarSize on the drawable, but that made the app force close. Instead, I searched through grepcode and found a few dimen files with different sizes for the action bar, so I added those to my own project's dimen files.
For values: 48dp
For values-land: 40dp
For values-sw600dp: 56dp
And after that, I think I looks great, notice on the screenshot how the listview and the actionbar don't overlap, and the transparent part of the listview is just the right size.
Hope that helps anyone who was wondering how to achieve this.

You can set a margin at the top of your layout, so that the content draws itself below the ActionBar.
Just add this in your parent layout:
android:layout_marginTop="?android:attr/actionBarSize"
The attribute actionBarSize refers to, like you would have already guessed, to the size of the ActionBar. You can't set an absolute value as a margin, since the ActionBar does not always have the same size across all Android devices (It's bigger on tablets, smaller on handset devices).
Edit:
Set the margin to the 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">
<FrameLayout
android:id="#+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ListView
android:id="#+id/left_drawer"
android:layout_marginTop="?android:attr/actionBarSize"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"/>
</android.support.v4.widget.DrawerLayout>
The Google Music app does the same:

I solved this problem using paddingTop:
<FrameLayout
android:id="#+id/menu_frame"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:paddingTop="?attr/actionBarSize" >
<ListView
android:id="#+id/left_drawer_list"
android:layout_width="240dp"
android:layout_height="match_parent" />
</FrameLayout>
Hope that helps

I have created a working demo following the above guide and tested on 2.x to 5.x
You can clone from Github
The important thing to play around is in Main Activity
toolbar = (Toolbar) findViewById(R.id.toolbar);
res = this.getResources();
this.setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setHomeButtonEnabled(true);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
{
ScrimInsetsFrameLayout scrimInsetsFrameLayout = (ScrimInsetsFrameLayout)
findViewById(R.id.linearLayout);
scrimInsetsFrameLayout.setOnInsetsCallback(this);
}
and the call back
#Override
public void onInsetsChanged(Rect insets) {
Toolbar toolbar = this.toolbar;
ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams)
toolbar.getLayoutParams();
lp.topMargin = insets.top;
int top = insets.top;
insets.top += toolbar.getHeight();
toolbar.setLayoutParams(lp);
insets.top = top; // revert
}
Absolutely the Theme for V21 does the magic
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- API 21 theme customizations can go here. -->
<item name="colorPrimary">#color/colorPrimary</item>
<item name="colorPrimaryDark">#color/colorPrimaryDark</item>
<item name="colorAccent">#color/accent_material_light</item>
<item name="windowActionModeOverlay">true</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:statusBarColor">#android:color/transparent</item>
<item name="android:windowTranslucentStatus">true</item>
</style>

Related

Can I have "adjustResize" soft keyboard behavior and a toolbar behind the status bar at the same time?

In my Android app, it is vital for me to use the adjustResize behavior for the soft keyboard. So users can scroll down to other UI elements, such as a "continue" button.
I've noticed that that adjustResize only works when I have both the Manifest setting and android:fitsSystemWindows="true" in the layout root element. (Please correct me if I'm wrong!)
But with android:fitsSystemWindows="true" the Toolbar no longer sits behind the Status Bar. Which makes perfect sense, but isn't what I want.
When the Toolbar sits behind it, the status bar has a matching darker shade of my Toolbar's color. What I have with android:fitsSystemWindows="true" is a colorless status bar and a toolbar that sits 24dp lower than I want it.
I will give up the matching colored Status Bar for the sake of the adjustResize keyboard behavior. But my question is, is it possible to have both? Dare I dream for both Beauty and Accessibility?
Anyone more experienced know the magical combination of settings?
Or perhaps, as a work around, a way to explicitly color the status bar?
fyi:
These are Activities with RelativeLayout root elements, and there are ListViews and EditTexts in some of them.
Toolbar is android.support.v7.widget.Toolbar
Potentially relevant Style items:
<style name="AppBaseTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="windowNoTitle">true</item>
<item name="windowActionBar">false</item>
<item name="android:windowContentOverlay">#null</item>
PS - I've read dozens of similar-ish questions on soft keyboard behavior, but was unable to find anything helpful on unintended effects to the Toolbar. Also vice versa, lots of Style questions about toolbar/statusbar behavior, but nothing seemingly relevant. Never the less, sorry if I missed something!
Many thanks in advance!
Edit
I've been playing with removing android:fitsSystemWindows="true" and adding more ScrollViews or trying to get everything into the same ScrollView. This does nothing.
If I remove android:fitsSystemWindows="true" then the bottom of the UI is "glued" to the bottom of the screen -- it does not "resize" to instead glue to the top of the soft keyboard like I would expect it to do with adjustResize set in the Manifest.
Setting android:fitsSystemWindows="true" in the root view makes the UI resize like I would expect -- but it also makes the toolbar no longer draw behind the statusBar.
So I am still exactly where I started :(
Adding a layout XML code sample:
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- CoordinatorLayout because this view uses SnackBars -->
<!-- Relative Layout to lock "continue" button bar to bottom -->
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- Main content, that scrolls with or without keyboard -->
<!-- Correctly sits behind transparent Status Bar -->
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="#dimen/footer_persistent_height">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- ACTUAL VIEWS DELETED FOR BREVITY / CLARITY -->
</RelativeLayout>
</android.support.v4.widget.NestedScrollView>
<!-- Bottom nav bar -->
<!-- Correctly sits at bottom of UI when keyboard is not visible -->
<!-- PROBLEM: Not accessible when soft keyboard is visible -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
style="?android:attr/buttonBarStyle">
<Button
android:id="#+id/skip_button"
android:theme="#style/ButtonContinueGrey"
android:onClick="skipClickHandler"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight=".5"
style="?android:attr/buttonBarButtonStyle"/>
<Button
android:id="#+id/button_progress"
android:theme="#style/ButtonContinueColored"
android:onClick="continueClickHandler"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight=".5"
style="?android:attr/buttonBarButtonStyle"/>
</LinearLayout>
</RelativeLayout>
</android.support.design.widget.CoordinatorLayout>
I have found a solution that seems to work well with the OS. First set fitSystemWindows = true to the view you want to be reacting to the window and then tell it to ignore the top padding:
ViewCompat.setOnApplyWindowInsetsListener(yourView, (view, insets) ->
ViewCompat.onApplyWindowInsets(yourView,
insets.replaceSystemWindowInsets(insets.getSystemWindowInsetLeft(), 0,
insets.getSystemWindowInsetRight(), insets.getSystemWindowInsetBottom()))
);
Read more here: https://medium.com/google-developers/why-would-i-want-to-fitssystemwindows-4e26d9ce1eec
I think you can try to use "adjustPan" instead of "adjustResize" when android:fitsSystemWindows="false". It works for me.
Try to keep your layout in scroll view and remove android:fitsSystemWindows="true" and use only adjust resize
I didn't got your question properly but as far I can understand to solve the problem-
For the padding problem try adding
android:fitsSystemWindows="true"
android:clipToPadding=”false”
And for the transparent status bar add
<item name="android:statusBarColor">#android:color/transparent</item>
to your AppTheme.
Hope it helps rest please upload the screenshot of your problem for detailed problem view.
(Answering my own question)
This does seem to be a bug in android:
https://code.google.com/p/android/issues/detail?id=63777
Posts on the above bug report link to a few suggested work arounds, like creating a custom Layout class or custom Soft Keyboard.
I feel like I've already wasted enough time with this. So my solution is to just manually color the Status Bar.
Solution:
Set android:fitsSystemWindows="true" in either the Layout's root view or globally in style.xml. This (along with adjustResize in the manifest) makes the UI shrink above the Soft Keyboard so no UI is blocked -- the most important thing.
Color the Status Bar. This is only possible in Lollypop and newer. Which is the same as the transparent StatusBar, anyway.
private void updateStatusBarColor(){
// Check Version
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
// OPTIONAL: Calculate a darker version of the toolbar color
int color = calculateDarkerColor(toolBarColor);
// Get the statusBar
Window window = getWindow();
// You can't color a transparent statusbar
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
// Set the color
window.setStatusBarColor(color);
}
}
// Calculate a darker version of a given color
// Note I do this because the color always changes, if it's always the same I would save the darker version as a Resource in colors.xml
private int calculateDarkerColor(int color){
float[] hsv = new float[3];
Color.colorToHSV(color, hsv);
hsv[2] *= 0.8f; // smaller = darker
return Color.HSVToColor(hsv);
}
Its working for me.
In manifest.xml, put this in <activity> tag.
android:windowSoftInputMode="adjustResize"
In your layout's parent tag, put this.
android:fitsSystemWindows="true"
android:clipToPadding="false"
In styles.xml, put this.
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowTranslucentNavigation">true</item>
I have done this with minSdkVersion 16 and targetSdkVersion 26
Here's what worked for me in order to have both a transparent status bar AND working adjustResize keyboard behavior.
First of all, I suggest you watch this 27-minute droidcon talk by Chris Banes, it can be enlightening: https://www.youtube.com/watch?v=_mGDMVRO3iE
In the layout add fitsSystemWindows on the correct level, so that the background image spreads under the status bar. Now fitsSystemWindows will fix the keyboard-layout behavior related to adjustResize.
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<!-- EditText etc here -->
In the Activity:
makeStatusBarTransparent(this);
setContentView(R.layout.activity_login);
The extension method:
fun Activity.makeStatusBarTransparent() {
window.apply {
clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
decorView.systemUiVisibility += View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
// or:
// decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
statusBarColor = Color.TRANSPARENT
}
}
In the activity tag in the manifest:
android:windowSoftInputMode="adjustResize|stateHidden"
I've decided to do ".systemUiVisibility += ..." so I can set some things like windowLightStatusBar on the theme through xml (I override it in different flavors). But you can specify the LIGHT_STATUS_BAR flag directly (or not, depending on your background).
Keep in mind that fitsSystemWindows overrides padding, so you need to use another layout if you use padding.
I have fix your issue, and also tested at my end. Please change your relative layout to framelayout like this:
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- CoordinatorLayout because this view uses SnackBars -->
<!-- Relative Layout to lock "continue" button bar to bottom -->
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<!-- Main content, that scrolls with or without keyboard -->
<!-- Correctly sits behind transparent Status Bar -->
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="24dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- ACTUAL VIEWS DELETED FOR BREVITY / CLARITY -->
</RelativeLayout>
</android.support.v4.widget.NestedScrollView>
<!-- Bottom nav bar -->
<!-- Correctly sits at bottom of UI when keyboard is not visible -->
<!-- PROBLEM: Not accessible when soft keyboard is visible -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
style="?android:attr/buttonBarStyle"
android:layout_gravity="bottom">
<Button
android:id="#+id/skip_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight=".5"
style="?android:attr/buttonBarButtonStyle"/>
<Button
android:id="#+id/button_progress"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight=".5"
style="?android:attr/buttonBarButtonStyle"/>
</LinearLayout>
</FrameLayout>
</android.support.design.widget.CoordinatorLayout>

Remove extra background color rectangle from overflow menu enter/exit animations?

When I open the overflow menu in my application, I see a solid rectangle of the menu background color displayed behind the menu itself throughout the enter/exit animations. Here's an animation showing this (slowed to 75% speed):
The presence of this extraneous colored rectangle spoils the nice enter/exit animations! How can I remove it while retaining all other Toolbar styling?
Research
I've read a bunch of answers on Toolbar styling on SO, and Chris Banes' own posts on the subject. It seems that usage of the style/theme tags on a per-View basis has changed in the past couple years, which has made it difficult to find definitive information anywhere.
I've reproduced this using versions 22.1.0 through 23.2.0 (inclusive) of the support library.
App files
styles.xml
<resources>
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="colorPrimary">#color/colorPrimary</item>
<item name="colorPrimaryDark">#color/colorPrimaryDark</item>
<item name="colorAccent">#color/colorAccent</item>
</style>
<style name="ToolbarStyle" parent="#style/ThemeOverlay.AppCompat.Dark.ActionBar">
<item name="android:background">#color/colorPrimary</item>
</style>
</resources>
activity_main.xml
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:style="#style/ToolbarStyle" />
<fragment
android:id="#+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
Runtime View Analysis
As #Commonsware suggested, I took a look at the view hierarchy at run time. Editing in the results:
Menu collapsed (overflow button present, no mysterious extra rectangle):
Menu expanded (overflow menu views displayed in separate Window):
The main application view hierarchy (as displayed in the original Window) is unchanged when comparing the two menu (steady) states. My guess is therefore that the extra rectangle is temporarily added to the main application's window during menu animations, and immediately removed upon their completion. I'm not sure why this would be done - perhaps it's a hangover from an older (and now unused) method of showing and hiding the overflow menu? If my deduction is correct, then this question could be resolved if we can determine how to prevent this transitory behavior...
An extract from the Chris Bane's answer to the question AppCompat style background propagated to the Image within the ToolBar
style = local to the Toolbar
theme = global to everything inflated in the Toolbar
Based on the above post it seems, the android:background attribute you are setting in the android:theme is the reason for the extra background color during the animation.
I'd set the background to the toolbar directly and used the android:colorBackground attribute to set the background color for the popup. The animation seems to work fine.
Code:
activity_main.xml
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/colorPrimary"
android:theme="#style/CustomToolbarTheme" />
styles.xml
<style name="CustomToolbarTheme" parent="ThemeOverlay.AppCompat.Dark.ActionBar">
<item name="android:colorBackground">#color/colorPrimary</item>
<item name="android:textColorPrimary">#android:color/white</item>
</style>

Android Toolbar too high in landscape mode

My min and target sdk is 21, and I am not using the support library.
I am using the new Toolbar widget, and generally it works, I just have a glitch in the way it looks. The action icons are centered in portrait mode, whereas the toolbar in landscape mode is higher, and the icons are not centered. Please take a look at the screenshots (read lines are just to make the problem more visible):
portrait:
landscape:
This might look like nothing, but when the actions are selected (like the 'up' arrow at the very left of the bar) the result is that a strip of few pixels below it is visible. I don't like the way it looks.
The activity does not manage any configuration changes itself.
This is my code:
styles.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="MyTheme" parent="android:Theme.Material.NoActionBar">
<item name="android:toolbarStyle">#style/MyToolbarStyle</item>
</style>
<style name="MyToolbarStyle" parent="android:Widget.Toolbar">
<item name="android:background">?android:attr/colorPrimary</item>
<item name="android:elevation">2dp</item>
</style>
</resources>
XML usage:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.test.TestActivity">
<Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</RelativeLayout>
I tried messing around with the android:minHeight attribute, but setting to so, say, 30dp just moved the icons even more upwards, also in portrait mode.
I found this: https://code.google.com/p/android/issues/detail?id=77874
But there is no ?attr/actionBarSize...
How, if at all, can this problem be fixed? The phone the screenshots were taken on is a Nexus 6 (xxxhdpi), and the icon is from the google icon pack, and the biggest resource is xxhdpi. Is this the problem?
Update: the workaround from the aforementioned link does work when I use ?android:attr/actionBarSize. But, is this the only way? Seems a bit wrong, to need such workarounds for a new shiny component like this, even more so that the workaround requires an attribute value for a component to be replaced by the new one.
try to use:
android:height="?android:attr/actionBarSize"
for your toolbar.
Add this in your toolbar style:
<item name="maxButtonHeight">?attr/actionBarSize</item>
I had the same problem with android.support.v7.widget.Toolbar.
My solution:
Put your toolbar into a RelativeLayout with the height you want for your toolbar. Set your toolbars layout_height to "wrap_content" and align it to the vertical center. I hope it helps.
<RelativeLayout
android:id="#+id/main_toolbar_relative_layout"
android:layout_width="match_parent"
android:layout_height="50dp"
>
<android.support.v7.widget.Toolbar
android:id="#+id/main_toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"
>
</android.support.v7.widget.Toolbar>
</RelativeLayout>

Coloring Android Status Bar in Nav Drawer

In this app I'm building, I've added a Navigation Drawer fragment into my activity. I'm using 5.0, so I've been able to set the primaryColor and primaryColorDark to get the right colors. I've decided to try and style my Nav Drawer to be very similar to Google Now's drawer in 5.0, where the Nav Drawer has it's own background for the status bar. (Can't post pictures, not enough reputation >.>)
I've followed this question's recommendations here, which has helped quite a bit. I've achieved drawing my Nav Drawer under the status bar when I pull it out. Only trouble is, I can't figure out how to set the color of the status bar that shows in my drawer. Currently, it just shows white.
Here are the relevant bits of my styles and code:
Activity Layout:
<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=".Main"
android:fitsSystemWindows="true">
<!-- main content -->
...
<!-- Drawer fragment -->
<fragment
android:id="#+id/navigation_drawer"
android:layout_width="#dimen/navigation_drawer_width"
android:layout_height="match_parent"
android:layout_gravity="left|start"
android:theme="#style/DrawerTheme"
android:fitsSystemWindows="true"
android:choiceMode="singleChoice"
android:name="com.myname.appname.NavigationDrawerFragment"
tools:layout="#layout/fragment_navigation_drawer" />
</android.support.v4.widget.DrawerLayout>
Fragment Layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/navDrawerFragment"
android:theme="#style/DrawerTheme"
android:background="#color/WindowBackground"
tools:context=".NavigationDrawerFragment"
android:fitsSystemWindows="true">
<!-- content here -->
</RelativeLayout>
Per link above, setting color of my status bar for the activity (this part works correctly):
public void onCreate(Bundled savedInstanceState) {
super.onCreate(savedInstanceState);
// ....
drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
drawerLayout.setDrawerShadow(R.drawable.drawer_shadow, Gravity.START);
drawerLayout.setStatusBarBackgroundColor(getResources().getColor(R.color.colorPrimaryDark));
// ....
}
And finally, my associated styles for the activity, and what I've 'tried' to assign to the fragment.
<style name="StatusBarActivityTheme" parent="MyAppTheme">
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:statusBarColor">#android:color/transparent</item>
</style>
<style name="DrawerTheme" parent="MyAppTheme">
<item name="android:statusBarColor">#000000</item>
<item name="android:colorPrimaryDark">#000000</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
</style>
Thanks in advance for any help you can send my way! I suspect my issue is related to do with how Google Now's primary screen has a transparent status bar, and only colors it during the Nav Drawer, but any news to the contrary would be great!
With the setup you have, the Nav Drawer is simply a view drawing its background (which you have defined as android:background="#color/WindowBackground") underneath the status bar (the color of which you have set to transparent via your StatusBarActivityTheme). The system only looks as far as the Activity theme to set the status bar color; assigning android:statusBarColor to a child has no effect.
The simple solution would be to change your Nav Drawer fragment layout's android:background to the color you desire. If you wish for the portion below your image to remain white, an option would be to then add an empty View in your drawer layout with android:background="#color/WindowBackground" or some other color.
If you desire for the content in your Nav Drawer to extend below the status bar, it requires a bit more work. The reason it is offset to begin with is because you set the android:fitsSystemWindows attribute to true, which in turn calls the view's default fitSystemWindows(). As the docs explain, this method takes the inset (i.e. the height of the status bar in our case) and applies it as the view's padding (in your case, this becomes top padding for the RelativeLayout of your Nav Drawer fragment).
One way to circumvent this padding is to overwrite the view's fitSystemWindows() method. I direct you to the open source IO Schedule app by Google - specifically, they used the ScrimInsetsScrollView as the root element in their Nav Drawer. This modified ScrollView applies a scrim of a color of your choice (set via the custom app:insetForeground attribute) and consumes the inset, i.e. no more padding!
The ScrimInsetsScrollView can be used as a model to write your own version for any View descendant, really - see the nigh identical ScrimInsetsFrameLayout.

Android, How to make a transparent status bar correctly

I'm trying to make transparent status bar on Android 4.4+
I know how to make it transparent by defining my own style:
<style name="Theme.MyTheme" parent="Theme.MyTheme.Base">
<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowTranslucentNavigation">true</item> </style>
I found here:
https://stackoverflow.com/a/20573595/2633630
The problem is that when status bar is transparent, it doesn't match the color of the action bar and the activity in the background is seen:
So I found that I can use android:fitsSystemWindows="true" and android:clipToPadding="false" in my layout that I found here http://mindofaandroiddev.wordpress.com/2013/12/28/making-the-status-bar-and-navigation-bar-transparent-with-a-listview-on-android-4-4-kitkat/
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/background_darkRed"
android:fitsSystemWindows="true"
android:clipToPadding="false"
tools:context="com.sandak.......">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
....
That solves the top problem with transparent status bar and looks ok.. Unfortunately there is problem at the bottom on the "nav bar" with the system buttons, which is red and not transparent as I wish:
I was trying all possible variants to achieve working result, but I cannot figure out how to solve it. My only working solution is set top padding about 60dp to the root element. But this solution is ugly and on different devices can look different and may be not working.
I found a few applications on Google Play which working Ok with transparent background, so I'm curious how they make it work.
For example:
https://play.google.com/store/apps/details?id=com.trello and few others
//UPDATE:
Ok, this is quite old answer. Now you can use Material theme to handle this and it is pretty easy. Just set target api to 21+, use support library if you need to and create theme with material theme where you can specify status bar color directly
<style name="AppTheme"
parent="Theme.AppCompat.Light.DarkActionBar">
<!-- colorPrimary is used for the default action bar background -->
<item name="colorPrimary">#color/color_primary</item>
<!-- colorPrimaryDark is used for the status bar -->
<item name="colorPrimaryDark">#color/color_primary_dark</item>
<!-- colorAccent is used as the default value for colorControlActivated
which is used to tint widgets -->
<item name="colorAccent">#color/accent_orange</item>
</style>
=======================================================================
OLD ANSWER:
Ok, It seems that I solve my problem. It is not the best and clearest solution, but it is working solution.
If anybody in the future will find out better and more clear solution, please let me know and I will update my answer / or mark your answer as correct one. But for now, I have no better solution than this little hack:
The root element of the layout has to be RelativeLayout. Than should follow your main layout like ScrollView or any kind of others layouts, it doesn't matter. At the end before closing Relative Layout tag follows empty LinearLayout which has set the same background as your Action Bar and fixed height (height of Status Bar).
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.sandak....">
<ScrollView
android:fitsSystemWindows="true"
android:clipToPadding="false"
android:layout_width="match_parent"
android:layout_height="match_parent">
.... all your main views etc..
</ScrollView>
<LinearLayout
android:id="#+id/statusBarBackgroundLinearLayout"
android:layout_width="match_parent"
android:orientation="horizontal"
android:layout_height="30dp"
android:background="#color/background_darkRed"
android:clickable="false"
android:focusable="false">
</LinearLayout>
</RelativeLayout>
Ok then you have to set in code the same Linear Layout height as the Status bar has:
private void setStatusBarBackground(View rootView) {
setStatusBarLayout(rootView);
statusBarHeight = getStatusBarHeight();
setStatusBarLayoutHeight(statusBarHeight);
}
private void setStatusBarLayout(View rootView){
statusBarBackgroundLinearLayout = (LinearLayout) rootView.findViewById(R.id.statusBarBackgroundLinearLayout);
if (isPreKitkatDevice()) {
hideStatusBarLayout();
}
}
private int getStatusBarHeight() {
int statusBarHeight = 0;
int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
statusBarHeight = getResources().getDimensionPixelSize(resourceId);
}
return statusBarHeight;
}
private boolean isPreKitkatDevice(){
return Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT;
}
private void hideStatusBarLayout(){
statusBarBackgroundLinearLayout.setVisibility(View.INVISIBLE);
}
private void setStatusBarLayoutHeight(int height){
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) statusBarBackgroundLinearLayout.getLayoutParams();
layoutParams.height = height;
}
And then just call setStatusBarBackground in your onCreate() method. This is working solution for all different kind of deviceas. For pre KitKat devices where transparent background is not allowed you have to hide the Linear Layout.

Categories

Resources