Translucent navigation without layout displaying beneath status bar - android

I am using the new Android 4.4 FLAG_TRANSLUCENT_NAVIGATION flag to turn the navigation bar (back, home button etc) at the bottom of the screen translucent. This works fine but a side effect of this is the layout of my Activity now displays beneath the status bar at the top of the screen (even though I have not set the status bar as being translucent). I want to avoid a hacky fix I.e. applying padding to the top of the layout.
Is there a way to set the navigation as translucent whilst ensuring the status bar appears normally and does NOT allow the layout to display beneath it?
The code I am using is as follows:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
Window w = getWindow();
w.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION, WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
}
Thanks

ianhanniballake's answer actually works, but you shouldn't use android:fitsSystemWindows="true" on the toplevel view. Use this property as following :
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#color/colorPrimaryDark">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#ffffff"
android:fitsSystemWindows="true">
<!-- Your other views -->
</LinearLayout>
</LinearLayout>
As you can see, you have to set the color on the top-level view, and put the property on another container.

Add android:fitsSystemWindows="true" to your top level view - android:fitsSystemWindows will automatically resize the view to take into account the system windows such as the status bar.

Related

Fragment's layout is too high with TabLayout + AppBarLayout

I'm struggled with this for hours looking for solution on google and stackoverflow. Thought that this is some trivial bug in my app but finally made empty project and can reproduce this too. Just run new project and select "Tabbed Activity" with navigation style "Action Bar Tabs (with ViewPager)
Then try to put any widget at the bottom of the fragment's layout. I did this by modify fragment_main.xml and adding:
android:layout_height="match_parent"
android:gravity="bottom"
android:textAlignment="center"
So the whole layout is:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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:id="#+id/constraintLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity$PlaceholderFragment">
<TextView
android:id="#+id/section_label"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="#dimen/activity_vertical_margin"
android:gravity="bottom"
android:text="aaaaaaa"
android:textAlignment="center"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="#+id/constraintLayout"
tools:layout_constraintLeft_creator="1"
tools:layout_constraintTop_creator="1" />
</android.support.constraint.ConstraintLayout>
In design mode everything looks fine:
But when you run app:
You will see text only when you swipe action bar to hide it:
So it is impossible to set widget at the bottom of the tab's fragment or even match some list/picture to the height of the parent because bottom edge will be always under navigation bar.
Workaround which I found is here:
ViewPager with Toolbar and TabLayout has wrong height
First one is to put AppBarLayout and ViewPager between LinearLayout but then I lose hidding action bar functionality when scrolling ViewPager's content. Second one is add android:paddingBottom="?attr/actionBarSize" in ViewPager but then there is a gap when I hide action bar. Seriously there is no solution for this?
I think this is an expected behavior since the ActionBar gets hidden when scrolling up. In the design mode the text can be shown because it doesn't display the TabLayout. However, when you launch the app, it will inflate the TabLayout and the fragment will go below it. So it's not like the fragment is getting expanded or giving you wrong height.
Imagine putting an ImageView that has a matching height of the visible field (from below the TabLayout to right above the navigation menu). When you hide action bar from there, it will have a gap on the bottom since there's no content to fill up the space of hidden action bar, unless you stretch the ImageView as you scroll up, which will result in wired stretched image :/
One possible solution I can think of is, if you want to add a view on the bottom of the fragment, I will set the actionbar padding to the view and when I scroll the screen, I will adjust the padding depends on the scroll offset so that I can always be on the bottom.

Transparent status bar overlaps action bar

Actual result: The status bar appears over the action bar Toolbar and the MenuItem inside the action bar is cut off. Note: "Test" is the action bar's title.
Expected result:
The top bound of the action bar Toolbar should appear directly below the bottom bound of the status bar and any MenuItems inside the action bar should be completely visible.
Activity's XML layout:
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/layout_root"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/image_background"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:src="#drawable/background"
tools:ignore="ContentDescription"/>
<android.support.v7.widget.Toolbar
android:id="#+id/action_bar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="#android:color/transparent"
android:fitsSystemWindows="true"
app:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"/>
</FrameLayout>
The action bar title and MenuItem are added at runtime.
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test);
setSupportActionBar((Toolbar) findViewById(R.id.action_bar));
ActionBar actionBar = getSupportActionBar();
assert actionBar != null;
actionBar.setDisplayHomeAsUpEnabled(false);
actionBar.setTitle("Test");
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_test, menu);
return true;
}
Before I added fitsSystemWindows="true" to the Toolbar view, the status bar still overlayed the action bar, but the 'SKIP' MenuItem was vertically centered in the action bar, causing it to appear partially underneath the status bar. I expected the fitsSystemWindows=true flag to give me my expected result (mentioned above), but it did not. It's as if fitsSystemWindows="true" correctly positioned the 'SKIP' button but did not adjust the position of the action bar itself. Anyone know what might be the issue here?
EDIT: I realize that I could remove fitsSystemWindows="true" and add a marginTop="...statusBarHeight" to the Toolbar view, but I am looking for the a cleaner way to solve this.
My issue was due to me setting the Toolbar's layout_height to ?attr/actionBarSize. I originally thought that fitsSystemWindows repositions the Toolbar, but it appears to add a padding instead. So when top padding is added to the Toolbar, the Toolbar's contents are pushed down. Since the Toolbar's height is fixed, the contents are pushed below the lower bound of the container. I ended up setting ?attr/actionBarSize as the value for the Toolbar's minHeight attribute to solve this. Below is my updated Toolbar:
<android.support.v7.widget.Toolbar
android:id="#+id/action_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize"
android:background="#android:color/transparent"
android:fitsSystemWindows="true"
app:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"/>
Caveat: This works if you aren't wanting to show anything directly below the action bar since the action bar's height, for one reason or another, is about twice the height that it needs to be to contain a single line of the home icon, title, and/or menu items. If anyone knows a way to achieve a non-overlapping status bar AND a normal size action bar, please share your insight. I would be forever grateful.
Caveat update: Okay. So apparently my action bar was receiving extra, bottom padding equivalent to the height of the navigation bar because I set <item name="android:windowTranslucentNavigation">true</item> on my Activity's theme. I verified this by removing the windowTranslucentNavigation attribute. I am testing this on a 7.1 Pixel using Android Support Libraries v25.1.1.
Try to move your Toolbar into AppBarLayout.
Like this:
<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/action_bar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="#android:color/transparent"
android:fitsSystemWindows="true"
app:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"/>
<AppBarLayout/>
I am using flags to make activity fullscreen and my style is NoActionBar.
If i set fitsSystemWindows=true to toolar or parent layout, activity content size changed because of navigation bar and status bar.
I wrapped ToolBar with AppBarLayout like in Twinkie_Monkey's answer and I set fitsSystemWindows=true to AppBarLayout and it worked.

Removing navigation view top padding in Android N Multi-Window mode

I would like to remove paddingTop/marginTop from the navigation view in Multi-Window mode of Android N. Like Gmail already does.
If you see the image below, I'm talking about the normal padding with size equals to the status bar at the beginning of the navigation view.
So basically in Multi-Window mode (see the image below) I have to remove that padding when my app is in the second part of the screen.
Unfortunately from the new api 24 you have isInMultiWindowMode() but it's not possible to know in which part of the screen is your app.
Instead of trying to figure out if you're in multi-window mode and on which part of the screen, you need to make your navigation view header respect system windows insets.
Normally you care about just one window - the one your app is drawn in. Usually you don't even think there are any windows. Isn't your app drawn fullscreen? Well, actually no. Usually there is some space reserved for system bars, like status bar at the top and navigation bar at the bottom. They are drawn in separate windows - system windows. (Oh, and now we've got multi-window mode in N. More like multi-app-window mode, because if you count system windows then multi-window has been around for a while.)
You can make your navigation view header adjust its insets depending on whether it is under a system window (in this case: status bar) or not with just a few simple tweaks.
Assuming the navigation view is defined like that:
<android.support.design.widget.NavigationView
...
android:fitsSystemWindows="true"
app:headerLayout="#layout/nav_header_main"
... />
and there is a simple header layout in nav_header_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="#dimen/nav_header_height"
android:background="#drawable/nav_header_background"
android:orientation="vertical"
android:paddingBottom="16dp"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingTop="32dp">
<ImageView
android:id="#+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#android:drawable/default_profile_picture" />
...
</LinearLayout>
you just need change it like that:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="#dimen/nav_header_height"
android:background="#drawable/nav_header_background"
android:fitsSystemWindows="true"
android:orientation="vertical">
<ImageView
android:id="#+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#android:drawable/sym_def_app_icon"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginTop="8dp"/>
...
</LinearLayout>
First you need to add android:fitsSystemWindows="true" to the layout.
Now you need to make top padding smaller, as fitsSystemWindows will automatically add padding the size of status bar. So previously your top padding was from the top of your header, now it is only from the bottom of the status bar.
And you have to move all your paddings from the layout somewhere else (for example I moved them to margins on child views), because fitsSystemWindows will overwrite those paddings.
After this if your app is in the bottom part of multi-window split then the padding for status bar will not be added. It will also make your navigation view look properly in any other cases where it's not under the status bar or if the status bar changes size in any future version of Android or some crazy custom ROM.
For me nothing was working so I ended up going this route and it got the job done:
<android.support.design.widget.NavigationView
...
app:insetForeground="#null"/>
Technically, the insets are still present but since the insetForeground resource used to draw on them is now null, that logic is skipped in ScrimInsetsFrameLayout's onDraw method (which is the parent class of NavigationView).
So when all else fails, this is a fairly efficient route.

How do I use DrawerLayout to display over the ActionBar/Toolbar and under the status bar on KitKat?

I've problems with implementing this guidelines in Kitkat. On Lollipop everything looks ok:
But on Kitkat Toolbar does not have any top padding:
I can fix this with https://github.com/jgilfelt/SystemBarTint library using:
SystemBarTintManager.SystemBarConfig config = tintManager.getConfig();
mainView.setPadding(0, config.getPixelInsetTop(false), config.getPixelInsetRight(), config.getPixelInsetBottom());
But I feel that I'm doing something wrong. Do you have any good practices how to achieve this effect on KitKat?
Move current layout resource in layout-v21 folder to have it as it is on the first screenshot. Then try to create new layout resource that will have just a placeholder view of same height of the status bar
Hierarchy should be following:
--Top layout
--<view layout_height="25dip"...>
-- Toolbar
-- the rest of the views
Using view аbove your Toolbar, will not push it behind the status bar, as it is on second screenshot and will mimick the padding you are trying to achieve
Do you have fitsSystemWindow set to true? Setting it to false will bring the toolbar back under the status bar.
The effect you see for Kitkat is because you have translucent status bar set and fitting to System Window goes underneath it.
For example, in your layout XML file:
<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"
android:background="#color/white"
android:fitsSystemWindows="false">
<android.support.v7.widget.Toolbar
android:background="#color/blue"
android:layout_width="match_parent"
android:layout_height="?android:attr/actionBarSize"
android:id="#+id/action_bar"/>
<!-- YOUR CONTENT HERE -->
<!-- YOUR NAVIGATION VIEW HERE -->
</android.support.v4.widget.DrawerLayout>

Status bar always on screen

Good day (or evening, or night)
I'm developing an app for android and I'm very curious about one thing. I have an activity, where user chats with another, like "im" chat. There are an EditText on the bottom and some kind of actionbar on the top. What I need is when user enters a message and the software keyboard is on screen, my activity should move up, but the actionbar should still be "glued" to the top of the screen, because it has some valuable controls on it.
Again, that's not an ActionBar, but just a 48dp height layout in a parent vertical linear layout. So I need to know is there an easy way to prevent it from moving to the top, when the layout moves off the screen.
I tried to put everything in a FrameLayout and put this bar on top of it, but on keyboard opens it goes off the screen too...
On you Activity at AndroidManifest you should put this: android:windowSoftInputMode="adjustResize"
Use something like this:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.myapp.MyActionBar
android:layout_width="match_parent"
android:layout_height="48dp"/>
<LinearLayout
android:id="#+id/mylayout"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1dp"/>
<!-- Add your edittext and button -->
</LinearLayout>
This will make sure the actionbar and edittext + button are allways on screen, and the mylayout takes up the rest of the screen. When your keyboard is shown, the mylayout will shrink.
Try adding android:windowSoftInputMode="adjustResize" to your activity in the manifest. This tells Android to completely resize your layout when the keyboard comes up, rather than pan it. Note that if there isn't enough room for the entire layout this still won't work. But you ought to be able to make it work if your top level layout is a RelativeLayout, with the edit text set to align bottom, the top bar to align top, and the middle section to fill_parent and be above the edit text and below the bar.
use a RelativeLayout as your base Layout and add android:layout_alignParentTop="true" to your action bar to keep it up
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<LinearLayout
android:id="#+id/action_bar_layout"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_alignParentTop="true" >
</LinearLayout>
<TextView
android:id="#+id/text_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true" />
</RelativeLayout>

Categories

Resources