24

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>
Kaitlyn Hanrahan
  • 759
  • 6
  • 22
  • I can't understand your problem correctly. Do you want to hide your toolbar when current view is scrolled? Your purpose of using adjustResize behaviour is for making your "continue" button accessible, have you tried to nest your RealtiveLayout inside NestedScrollView instead? You can control your statusBar color by setting ColorPrimaryDark in your theme, if you are >= Lollipop – Wiktor Wardzichowski Mar 07 '17 at 09:22
  • 1
    Try to keep your layout in scroll view and remove android:fitsSystemWindows="true" and use only adjust resize – Varun Jain Mar 07 '17 at 19:54
  • fitsSystemWindow simply draws your views behind the statusbar. possible duplicate? http://stackoverflow.com/questions/37454733/status-bar-color-not-changing-with-relative-layout-as-root-element Can you post an example layout - there are a lot of combinations that can be causing the problem. – ayvazj Mar 08 '17 at 08:31
  • @VarunJain if you can quickly make your comment and answer, I will give you the bounty! (it expires in less than an hour) – Kaitlyn Hanrahan Mar 09 '17 at 16:25
  • I'm having the exact same problem, did you find a solution that doesnt involve tinting the status bar (what I'm trying to draw behind the statusbar is not a solid color) – frankelot Feb 02 '18 at 05:25

8 Answers8

19

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

frankelot
  • 13,666
  • 16
  • 54
  • 89
  • 6
    Excellent answer. – Bolling Jul 26 '18 at 09:11
  • 1
    I passed on this answer at first because I wasn't ready to mess with insets, but it actually was exactly what I needed. If Android Studio's layout inspector reports an unexplained non-zero value in one of the "mPadding" field (as opposed to the "mUserPadding" fields) after setting fitsSystemWindows to true, this might be the solution, as it was in my case. – Ronan Mar 13 '19 at 21:50
2

I think you can try to use "adjustPan" instead of "adjustResize" when android:fitsSystemWindows="false". It works for me.

Hexise
  • 1,520
  • 15
  • 20
1

Try to keep your layout in scroll view and remove android:fitsSystemWindows="true" and use only adjust resize

Varun Jain
  • 171
  • 2
  • 14
  • Glad someone was able to get the bounty :) I didn't have time to fully try out your solution before the bounty was expiring. Your simple solution does get the StatusBar the way I wanted, and I can scroll... but I can only scroll to the parts of the UI inside the ScrollView. The "continue" button, which is purposely outside the ScrollView is not accessible with the keyboard viewable. I added a code sample to the question -- would you please give it a look and tell me if you have any idea? Thank you! – Kaitlyn Hanrahan Mar 10 '17 at 14:36
  • I tried wrapping the outer RelativeLayout in another ScrollView, but then the Continue Button was no longer at the bottom of the screen, it was at the bottom of the content. – Kaitlyn Hanrahan Mar 10 '17 at 14:36
  • Haha...yes thanks for the bounty, i have just added a answer by little modification in your layout which will fix your problem...for future support if you need instant support just ping me on my whatsapp number :- +91-8585949830 – Varun Jain Mar 10 '17 at 16:50
  • 2
    Can you elaborate your answer a bit more.... adjustResize doesn't seem to do anything for me unless I also use "fitSystemWindows". Thanks :) – frankelot Feb 02 '18 at 05:21
  • @FRR Can you please post something relevant to the solution here – Gaurav Arora Jul 19 '20 at 03:29
0

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.

Manmeet Singh
  • 429
  • 1
  • 4
  • 11
  • clipToPadding solved my issue where the activity using fitsSystemWindows="false" and a fragment using fitsSystemWindows="true"... along with windowSoftInputMode="adjustResize" on the activity. Before setting the clipTopPadding="false" I was seeing unessessary padding under the toolbar, which clipped the fragments content. – Codeversed May 22 '18 at 13:25
0

(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:

  1. 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.

  2. 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);
    }
    
Kaitlyn Hanrahan
  • 759
  • 6
  • 22
  • 1
    However this only works if the status bar is a solid color, not if you want to have content actually behind the status bar :( – htafoya Jan 15 '18 at 07:00
0

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

import random
  • 3,054
  • 1
  • 17
  • 22
suhasini
  • 39
  • 4
0

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.

Stan
  • 2,151
  • 1
  • 25
  • 33
-1

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>
halfer
  • 19,824
  • 17
  • 99
  • 186
Varun Jain
  • 171
  • 2
  • 14
  • This does not seem to make any difference. What version of Android did this give you both (1) a bottom button bar that is visible above soft keyboard and (2) a transparent statusbar? – Kaitlyn Hanrahan Mar 10 '17 at 17:28
  • but i have test in marshmallow in samsung edge s6..using above code and on opening softkeyboard bottom layout come up with keyboard and on hide the keyboard bottom layout goes down... – Varun Jain Mar 10 '17 at 17:34