197

I have researched a lot to adjust the layout when softkeyboard is active and I have successfully implemented it but the problem comes when I use android:theme="@android:style/Theme.NoTitleBar.Fullscreen" this in my activity tag in manifest file.

For this I have used android:windowSoftInputMode="adjustPan|adjustResize|stateHidden" with different options but no luck.

After that I implemented FullScreen programmatically and tried various layout to work with FullScreen but all in vain.

I referred these links and have looked many posts here related to this issue:

http://android-developers.blogspot.com/2009/04/updating-applications-for-on-screen.html

http://davidwparker.com/2011/08/30/android-how-to-float-a-row-above-keyboard/

Here is xml code:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout android:id="@+id/masterContainerView"
    android:layout_width="fill_parent" android:layout_height="fill_parent"
    android:orientation="vertical" xmlns:android="http://schemas.android.com/apk/res/android"
    android:background="#ffffff">

    <ScrollView android:id="@+id/parentScrollView"
        android:layout_width="fill_parent" android:layout_height="wrap_content">

        <LinearLayout android:layout_width="fill_parent"
            android:layout_height="fill_parent" android:orientation="vertical">

            <TextView android:id="@+id/setup_txt" android:layout_width="wrap_content"
                android:layout_height="wrap_content" android:text="Setup - Step 1 of 3"
                android:textColor="@color/top_header_txt_color" android:textSize="20dp"
                android:padding="8dp" android:gravity="center_horizontal" />

            <TextView android:id="@+id/txt_header" android:layout_width="fill_parent"
                android:layout_height="40dp" android:text="AutoReply:"
                android:textColor="@color/top_header_txt_color" android:textSize="14dp"
                android:textStyle="bold" android:padding="10dp"
                android:layout_below="@+id/setup_txt" />

            <EditText android:id="@+id/edit_message"
                android:layout_width="fill_parent" android:layout_height="wrap_content"
                android:text="Some text here." android:textSize="16dp"
                android:textColor="@color/setting_editmsg_color" android:padding="10dp"
                android:minLines="5" android:maxLines="6" android:layout_below="@+id/txt_header"
                android:gravity="top" android:scrollbars="vertical"
                android:maxLength="132" />

            <ImageView android:id="@+id/image_bottom"
                android:layout_width="fill_parent" android:layout_height="wrap_content"
                android:layout_below="@+id/edit_message" />

        </LinearLayout>
    </ScrollView>

    <RelativeLayout android:id="@+id/scoringContainerView"
        android:layout_width="fill_parent" android:layout_height="50px"
        android:orientation="vertical" android:layout_alignParentBottom="true"
        android:background="#535254">

        <Button android:id="@+id/btn_save" android:layout_width="wrap_content"
            android:layout_height="wrap_content" android:layout_alignParentRight="true"
            android:layout_marginTop="7dp" android:layout_marginRight="15dp"
            android:layout_below="@+id/edit_message"
            android:text = "Save" />

        <Button android:id="@+id/btn_cancel" android:layout_width="wrap_content"
            android:layout_height="wrap_content" android:layout_marginTop="7dp"
            android:layout_marginRight="10dp" android:layout_below="@+id/edit_message"
            android:layout_toLeftOf="@+id/btn_save" android:text = "Cancel" />

    </RelativeLayout>
</RelativeLayout>

enter image description here

I want the bottom 2 buttons should go upward when the softkeyboard comes in picture.

enter image description here

5
  • 1
    I think you have to add Buttons inside ScrollView and below EditText. Sep 14, 2011 at 14:44
  • I have already tried many options that does not work ... Sep 14, 2011 at 15:01
  • 1
    put ur buttons in a framelayout and set the weight of the framelayout to 1 and finally use only android:windowSoftInputMode="adjustPan" tell me if this work.. Sep 20, 2011 at 15:19
  • @VineetShukla have you found any work out with full screen?? Apr 29, 2013 at 11:00
  • 4
    Notice that you shouldn't use adjustResize and adjustPan at the same time, from the javadoc of android.view.WindowManager.LayoutParams#SOFT_INPUT_ADJUST_RESIZE: "This can not be combined with{@link SOFT_INPUT_ADJUST_PAN}" Sep 19, 2014 at 8:54

29 Answers 29

279

Based on yghm's workaround, I coded up a convenience class that allows me to solve the problem with a one-liner (after adding the new class to my source code of course). The one-liner is:

     AndroidBug5497Workaround.assistActivity(this);

And the implementation class is:


public class AndroidBug5497Workaround {
    
    // For more information, see https://issuetracker.google.com/issues/36911528
    // To use this class, simply invoke assistActivity() on an Activity that already has its content view set.

    public static void assistActivity (Activity activity) {
        new AndroidBug5497Workaround(activity);
    }
    
    private View mChildOfContent;
    private int usableHeightPrevious;
    private FrameLayout.LayoutParams frameLayoutParams;

    private AndroidBug5497Workaround(Activity activity) {
        FrameLayout content = (FrameLayout) activity.findViewById(android.R.id.content);
        mChildOfContent = content.getChildAt(0);
        mChildOfContent.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            public void onGlobalLayout() {
                possiblyResizeChildOfContent();
            }
        });
        frameLayoutParams = (FrameLayout.LayoutParams) mChildOfContent.getLayoutParams();
    }

    private void possiblyResizeChildOfContent() {
        int usableHeightNow = computeUsableHeight();
        if (usableHeightNow != usableHeightPrevious) {
            int usableHeightSansKeyboard = mChildOfContent.getRootView().getHeight();
            int heightDifference = usableHeightSansKeyboard - usableHeightNow;
            if (heightDifference > (usableHeightSansKeyboard/4)) {
                // keyboard probably just became visible
                frameLayoutParams.height = usableHeightSansKeyboard - heightDifference;
            } else {
                // keyboard probably just became hidden
                frameLayoutParams.height = usableHeightSansKeyboard;
            }
            mChildOfContent.requestLayout();
            usableHeightPrevious = usableHeightNow;
        }
    }

    private int computeUsableHeight() {
        Rect r = new Rect();
        mChildOfContent.getWindowVisibleDisplayFrame(r);
        return (r.bottom - r.top);
    }
}

30
  • 10
    Thanks! I have no idea why, but I had to replace return (r.bottom - r.top); with return r.bottom to get it work on my HTC One Mini, otherwise the activity view would be pushed too high by the size of the status bar. I haven't tested it on another device yet though. Hope that can help.
    – Joan
    Jul 15, 2014 at 14:21
  • 5
    Hi Joseph johnson, I used your code and it worked perfectly. But now days facing an issue on some small devices that it shows the gap (blank screen) between keyboard and layout. Have you any idea about this issue? I also tried return r.bottom.
    – Pankaj
    Sep 26, 2014 at 12:42
  • 2
    Joseph Johnson : I have implemented your method, its working fine when we click on the top edit text but when we click on bottom edittext all design goes up
    – ranjith
    Oct 16, 2014 at 12:16
  • 3
    Unfortunately it doesn't work on Nexus 7 (2013). It still pans even with adjustNothing set. Nov 30, 2014 at 2:01
  • 6
    Awesome answer, thank you very much. It's working on a Nexus 6 but instead of using frameLayoutParams.height = usableHeightSansKeyboard; i have to use frameLayoutParams.height = usableHeightNow; If I don't this some elements falls outside the screen. May 19, 2016 at 2:41
45

Since the answer has already been picked and problem known to be a bug, I thought I would add a "Possible Work Around".

You can toggle fullScreen mode when soft keyboard is shown. This allows the "adjustPan" to work correctly.

In other words, I still use @android:style/Theme.Black.NoTitleBar.Fullscreen as part of the application theme and stateVisible|adjustResize as part of the activity window soft input mode but to get them to work together I must toggle fullscreen mode before the keyboard comes up.

Use the following Code:

Turn Off full screen mode

getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);

Turn On full screen mode

getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);

Note - inspiration came from: Hiding Title in a Fullscreen mode

4
28

I tried the solution from Joseph Johnson, but like others I ran into the gap-between-content-and-keyboard problem. The problem occurs because the soft input mode is always pan when using full-screen mode. This panning interferes with Joseph's solution when you activate an input field that would be hidden by the soft input.

When the soft input appears, the content is first panned based on its original height, and then resized by the layout requested by the Joseph's solution. The resizing and subsequent layout do not undo the panning, which results in the gap. The full order of events is:

  1. Global layout listener
  2. Panning
  3. Layout of content (= actual resizing of content)

It is not possible to disable panning, but it is possible to force the pan offset to be 0 by changing the height of the content. This can be done in the listener, because it is run before panning takes place. Setting the content height to the available height results in a smooth user experience, i.e. no flickering.

I also made these changes. If any of these introduce issues, let me know:

  • Switched determination of available height to use getWindowVisibleDisplayFrame. The Rect is cached to prevent a little bit of unneeded garbage.
  • Allow the listener to be removed too. This is useful when you reuse an activity for different fragments having different full-screen requirements.
  • Do not distinguish between keyboard shown or hidden, but always set the content height to the visible display frame height.

It has been tested on a Nexus 5, and emulators running API levels 16-24 with screen sizes ranging from tiny to big.

The code has been ported to Kotlin, but porting my changes back to Java is simple. Let me know if you need help:

class AndroidBug5497Workaround constructor(activity: Activity) {
    private val contentContainer = activity.findViewById(android.R.id.content) as ViewGroup
    private val rootView = contentContainer.getChildAt(0)
    private val rootViewLayout = rootView.layoutParams as FrameLayout.LayoutParams
    private val viewTreeObserver = rootView.viewTreeObserver
    private val listener = ViewTreeObserver.OnGlobalLayoutListener { possiblyResizeChildOfContent() }

    private val contentAreaOfWindowBounds = Rect()
    private var usableHeightPrevious = 0

    // I call this in "onResume()" of my fragment
    fun addListener() {
        viewTreeObserver.addOnGlobalLayoutListener(listener)
    }

    // I call this in "onPause()" of my fragment
    fun removeListener() {
        viewTreeObserver.removeOnGlobalLayoutListener(listener)
    }

    private fun possiblyResizeChildOfContent() {
        contentContainer.getWindowVisibleDisplayFrame(contentAreaOfWindowBounds)
        val usableHeightNow = contentAreaOfWindowBounds.height()
        if (usableHeightNow != usableHeightPrevious) {
            rootViewLayout.height = usableHeightNow
            // Change the bounds of the root view to prevent gap between keyboard and content, and top of content positioned above top screen edge.
            rootView.layout(contentAreaOfWindowBounds.left, contentAreaOfWindowBounds.top, contentAreaOfWindowBounds.right, contentAreaOfWindowBounds.bottom)
            rootView.requestLayout()

            usableHeightPrevious = usableHeightNow
        }
    }
}
7
  • 10
    This seems to be the best answer. I ported to java here gist.github.com/grennis/2e3cd5f7a9238c59861015ce0a7c5584 . Note I was getting exceptions that observer was not alive, and had to check for that as well.
    – Greg Ennis
    Apr 27, 2017 at 14:56
  • 1
    Oh my god! been traversing all system views hierarchy looking for that Ghost space. I was close to ditch computers for a food truck but saw your answer in the last minute. It works :)
    – rupps
    Mar 16, 2018 at 15:27
  • @GregEnnis, thanks, your solution works with onResume(), onPause(), onDestroy() (see comments in GitHub code).
    – CoolMind
    Oct 17, 2018 at 12:14
  • This is working for me, except that the removeListener call doesn't seem to be working. I put breakpoints inside both the possiblyResizeChildOfContent call and the removeListener call, and even after i hit the removeListener breakpoint, possiblyResizeChildOfContent is still being called. Anyone else having this issue?
    – Quinn
    Mar 6, 2019 at 15:27
  • Okay, I fixed my issue by simply specifying the type of the listener like so private val listener = ViewTreeObserver.OnGlobalLayoutListener { possiblyResizeChildOfContent() }. I guess without the type it wasn't being removed properly.
    – Quinn
    Mar 6, 2019 at 15:49
16

I just found a simple and reliable solution if you are using the system UI approach (https://developer.android.com/training/system-ui/immersive.html).

It works in the case when you are using View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN, e.g. if you are using CoordinatorLayout.

It won't work for WindowManager.LayoutParams.FLAG_FULLSCREEN (The one you can also set in theme with android:windowFullscreen), but you can achieve similar effect with SYSTEM_UI_FLAG_LAYOUT_STABLE (which "has the same visual effect" according to the docs) and this solution should work again.

getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN
                    | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION /* If you want to hide navigation */
                    | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE)

I've tested it on my device running Marshmallow.

The key is that soft keyboards are also one of the system windows (such as status bar and navigation bar), so the WindowInsets dispatched by system contains accurate and reliable information about it.

For the use case such as in DrawerLayout where we are trying to draw behind the status bar, We can create a layout that ignores only the top inset, and applies the bottom inset which accounts for the soft keyboard.

Here is my custom FrameLayout:

/**
 * Implements an effect similar to {@code android:fitsSystemWindows="true"} on Lollipop or higher,
 * except ignoring the top system window inset. {@code android:fitsSystemWindows="true"} does not
 * and should not be set on this layout.
 */
public class FitsSystemWindowsExceptTopFrameLayout extends FrameLayout {

    public FitsSystemWindowsExceptTopFrameLayout(Context context) {
        super(context);
    }

    public FitsSystemWindowsExceptTopFrameLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public FitsSystemWindowsExceptTopFrameLayout(Context context, AttributeSet attrs,
                                                 int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    public FitsSystemWindowsExceptTopFrameLayout(Context context, AttributeSet attrs,
                                                 int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    public WindowInsets onApplyWindowInsets(WindowInsets insets) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            setPadding(insets.getSystemWindowInsetLeft(), 0, insets.getSystemWindowInsetRight(),
                    insets.getSystemWindowInsetBottom());
            return insets.replaceSystemWindowInsets(0, insets.getSystemWindowInsetTop(), 0, 0);
        } else {
            return super.onApplyWindowInsets(insets);
        }
    }
}

And to use it:

<com.example.yourapplication.FitsSystemWindowsExceptTopFrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <!-- Your original layout here -->
</com.example.yourapplication.FitsSystemWindowsExceptTopFrameLayout>

This should theoretically work for any device without insane modification, much better than any hack that tries to take a random 1/3 or 1/4 of screen size as reference.

(It requires API 16+, but I'm using fullscreen only on Lollipop+ for drawing behind the status bar so it's the best solution in this case.)

1
  • Although the API needs to be modified, this is really a good solution. It feels very close to Google’s design philosophy. It’s a pity that no one liked it, maybe you didn’t explain it clearly enough.
    – 王 能
    Dec 4, 2023 at 8:04
10

Please note that android:windowSoftInputMode="adjustResize" does not work when WindowManager.LayoutParams.FLAG_FULLSCREENis set for an activity. You've got two options.

  1. Either disable fullscreen mode for your activity. Activity is not re-sized in fullscreen mode. You can do this either in xml (by changing the theme of the activity) or in Java code. Add the following lines in your onCreate() method.

    getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);   
    getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);`
    

OR

  1. Use an alternative way to achieve fullscreen mode. Add the following code in your onCreate() method.

    getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
    getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
    getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
    View decorView = getWindow().getDecorView();
    // Hide the status bar.
    int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN;
    decorView.setSystemUiVisibility(uiOptions);`
    

Please note that method-2 only works in Android 4.1 and above.

3
  • @AnshulTyagi method-2 only works in Android 4.1 and above. Jun 30, 2015 at 11:52
  • 4
    Tested on 5.0 and 4.4.2, Nexus 9 and Samsung s4 respectively, 2nd method does not work.
    – RobVoisey
    Oct 29, 2015 at 12:05
  • 2
    2nd method simply does not work and I wasted a lot of time on it.
    – Greg Ennis
    Apr 27, 2017 at 14:18
9

I had to face this problem too and had a work around which i checked on HTC one, galaxy s1, s2, s3, note and HTC sensation.

put a global layout listener on the root view of your layout

mRootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener(){
            public void onGlobalLayout() {
                checkHeightDifference();
            }
    });

and in there i checked the height difference and if the height difference of the screen is bigger then a third on the screen height then we can assume the keyboard is open. took it from this answer.

private void checkHeightDifference(){
    // get screen frame rectangle 
    Rect r = new Rect();
    mRootView.getWindowVisibleDisplayFrame(r);
    // get screen height
    int screenHeight = mRootView.getRootView().getHeight();
    // calculate the height difference
    int heightDifference = screenHeight - (r.bottom - r.top);

    // if height difference is different then the last height difference and
    // is bigger then a third of the screen we can assume the keyboard is open
    if (heightDifference > screenHeight/3 && heightDifference != mLastHeightDifferece) {
        // keyboard visiblevisible
        // get root view layout params
        FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mRootView.getLayoutParams();
        // set the root view height to screen height minus the height difference
        lp.height = screenHeight - heightDifference;
        // call request layout so the changes will take affect
        .requestLayout();
        // save the height difference so we will run this code only when a change occurs.
        mLastHeightDifferece = heightDifference;
    } else if (heightDifference != mLastHeightDifferece) {
        // keyboard hidden
        PFLog.d("[ChatroomActivity] checkHeightDifference keyboard hidden");
        // get root view layout params and reset all the changes we have made when the keyboard opened.
        FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mRootView.getLayoutParams();
        lp.height = screenHeight;
        // call request layout so the changes will take affect
        mRootView.requestLayout();
        // save the height difference so we will run this code only when a change occurs.
        mLastHeightDifferece = heightDifference;
    }
}

this is probably not bullet proof and maybe on some devices it will not work but it worked for me and hope it will help you too.

1
  • 1
    Needed some adjustements, but it worked. In the Nexus 7 2013 I had to decrease the keyboard height (screenHeight/3) by some pixels. Nice idea, thanks!
    – Joao Sousa
    Nov 4, 2013 at 15:35
9

Add android:fitsSystemWindows="true" to the layout, and this layout will resize.

3
  • That's what solved it for me. In addition thought, make sure you set it on the right view. If you have a background that should go below the status bar, don't set it there, but on a layout inside. Probably EditText views etc should be inside that second layout inside. Also watch this talk, as it makes things more clear: youtube.com/watch?v=_mGDMVRO3iE
    – Stan
    Dec 30, 2019 at 16:40
  • 1
    Worked for me as well. Thanks to @Stan comment I also was able to make it work with FULLSCREEN theme placing that attribute on the ViewPager instead of the activity/fragment layout. Mar 3, 2020 at 11:12
  • Worked perfectly for me. I put it on the top of my layout in my fragment and now the fullscreen theme works fine with the adjustResize flag. Wonky. Jul 2, 2021 at 17:55
8

I implemented Joseph Johnson solution and it worked well, I noticed after using this solution sometimes the drawer on the application will not close properly. I added a functionality to remove the listener removeOnGlobalLayoutListener when the user closes the fragment where are edittexts located.

    //when the application uses full screen theme and the keyboard is shown the content not scrollable! 
//with this util it will be scrollable once again
//http://stackoverflow.com/questions/7417123/android-how-to-adjust-layout-in-full-screen-mode-when-softkeyboard-is-visible
public class AndroidBug5497Workaround {


    private static AndroidBug5497Workaround mInstance = null;
    private View mChildOfContent;
    private int usableHeightPrevious;
    private FrameLayout.LayoutParams frameLayoutParams;
    private ViewTreeObserver.OnGlobalLayoutListener _globalListener;

    // For more information, see https://code.google.com/p/android/issues/detail?id=5497
    // To use this class, simply invoke assistActivity() on an Activity that already has its content view set.

    public static AndroidBug5497Workaround getInstance (Activity activity) {
        if(mInstance==null)
        {
            synchronized (AndroidBug5497Workaround.class)
            {
                mInstance = new AndroidBug5497Workaround(activity);
            }
        }
        return mInstance;
    }

    private AndroidBug5497Workaround(Activity activity) {
        FrameLayout content = (FrameLayout) activity.findViewById(android.R.id.content);
        mChildOfContent = content.getChildAt(0);
        frameLayoutParams = (FrameLayout.LayoutParams) mChildOfContent.getLayoutParams();

        _globalListener = new ViewTreeObserver.OnGlobalLayoutListener()
        {

            @Override
            public void onGlobalLayout()
            {
                 possiblyResizeChildOfContent();
            }
        };
    }

    public void setListener()
    {
         mChildOfContent.getViewTreeObserver().addOnGlobalLayoutListener(_globalListener);
    }

    public void removeListener()
    {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            mChildOfContent.getViewTreeObserver().removeOnGlobalLayoutListener(_globalListener);
        } else {
            mChildOfContent.getViewTreeObserver().removeGlobalOnLayoutListener(_globalListener);
        }
    }

    private void possiblyResizeChildOfContent() {
        int usableHeightNow = computeUsableHeight();
        if (usableHeightNow != usableHeightPrevious) {
            int usableHeightSansKeyboard = mChildOfContent.getRootView().getHeight();
            int heightDifference = usableHeightSansKeyboard - usableHeightNow;
            if (heightDifference > (usableHeightSansKeyboard/4)) {
                // keyboard probably just became visible
                frameLayoutParams.height = usableHeightSansKeyboard - heightDifference;
            } else {
                // keyboard probably just became hidden
                frameLayoutParams.height = usableHeightSansKeyboard;
            }
            mChildOfContent.requestLayout();
            usableHeightPrevious = usableHeightNow;
        }
    }

    private int computeUsableHeight() {
        Rect r = new Rect();
        mChildOfContent.getWindowVisibleDisplayFrame(r);
        return (r.bottom - r.top);
    } 
}

uses the class where is my edittexts located

@Override
public void onStart()
{
    super.onStart();
    AndroidBug5497Workaround.getInstance(getActivity()).setListener();
}

@Override
public void onStop()
{
    super.onStop();
    AndroidBug5497Workaround.getInstance(getActivity()).removeListener();
}
7

I'm currently using this approach and it works like a charm. The trick is we get keyboard height from different methods on 21 above and below and then use it as the bottom padding of our root view in our activity. I assumed your layout does not need a top padding (goes below status bar) but in case you do, inform me to update my answer.

MainActivity.java

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        RelativeLayout mainLayout = findViewById(R.id.main_layout);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            ViewCompat.setOnApplyWindowInsetsListener(mainLayout , new OnApplyWindowInsetsListener() {
                @Override
                public WindowInsetsCompat onApplyWindowInsets(View v, WindowInsetsCompat insets) {
                    v.setPadding(0, 0, 0, insets.getSystemWindowInsetBottom());
                    return insets;
                }
            });
        } else {
            View decorView = getWindow().getDecorView();
            final View contentView = mainLayout;
            decorView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
                @Override
                public void onGlobalLayout() {
                    Rect r = new Rect();
                    //r will be populated with the coordinates of your view that area still visible.
                    decorView.getWindowVisibleDisplayFrame(r);

                    //get screen height and calculate the difference with the useable area from the r
                    int height = decorView.getContext().getResources().getDisplayMetrics().heightPixels;
                    int diff = height - r.bottom;

                    //if it could be a keyboard add the padding to the view
                    if (diff != 0) {
                        // if the use-able screen height differs from the total screen height we assume that it shows a keyboard now
                        //check if the padding is 0 (if yes set the padding for the keyboard)
                        if (contentView.getPaddingBottom() != diff) {
                            //set the padding of the contentView for the keyboard
                            contentView.setPadding(0, 0, 0, diff);
                        }
                    } else {
                        //check if the padding is != 0 (if yes reset the padding)
                        if (contentView.getPaddingBottom() != 0) {
                            //reset the padding of the contentView
                            contentView.setPadding(0, 0, 0, 0);
                        }
                    }
                }
            });
        }
    }
...
}

Don't forget to address your root view with an id:

activity_main.xml

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/main_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

Hope it helps someone.

1
  • 1
    Can't understand, why this answer is still not in top. That others ones glitch, flash, but this one is brilliant, especially if you have 5+ api. Jul 7, 2020 at 11:45
5

To get it to work with FullScreen:

Use the ionic keyboard plugin. This allows you to listen for when the keyboard appears and disappears.

OnDeviceReady add these event listeners:

// Allow Screen to Move Up when Keyboard is Present
window.addEventListener('native.keyboardshow', onKeyboardShow);
// Reset Screen after Keyboard hides
window.addEventListener('native.keyboardhide', onKeyboardHide);

The Logic:

function onKeyboardShow(e) {
    // Get Focused Element
    var thisElement = $(':focus');
    // Get input size
    var i = thisElement.height();
    // Get Window Height
    var h = $(window).height()
    // Get Keyboard Height
    var kH = e.keyboardHeight
    // Get Focused Element Top Offset
    var eH = thisElement.offset().top;
    // Top of Input should still be visible (30 = Fixed Header)
    var vS = h - kH;
    i = i > vS ? (vS - 30) : i;
    // Get Difference
    var diff = (vS - eH - i);
    if (diff < 0) {
        var parent = $('.myOuter-xs.myOuter-md');
        // Add Padding
        var marginTop = parseInt(parent.css('marginTop')) + diff - 25;
        parent.css('marginTop', marginTop + 'px');
    }
}

function onKeyboardHide(e) {
  // Remove All Style Attributes from Parent Div
  $('.myOuter-xs.myOuter-md').removeAttr('style');
}

Basically if they difference is minus then that is the amount of pixels that the keyboard is covering of your input. So if you adjust your parent div by this that should counteract it.

Adding timeouts to the logic say 300ms should also optimise performance (as this will allow keyboard time to appear.

5

1) Create KeyboardHeightHelper:

public class KeyboardHeightHelper {

    private final View decorView;
    private int lastKeyboardHeight = -1;

    public KeyboardHeightHelper(Activity activity, View activityRootView, OnKeyboardHeightChangeListener listener) {
        this.decorView = activity.getWindow().getDecorView();
        activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(() -> {
            int keyboardHeight = getKeyboardHeight();
            if (lastKeyboardHeight != keyboardHeight) {
                lastKeyboardHeight = keyboardHeight;
                listener.onKeyboardHeightChange(keyboardHeight);
            }
        });
    }

    private int getKeyboardHeight() {
        Rect rect = new Rect();
        decorView.getWindowVisibleDisplayFrame(rect);
        return decorView.getHeight() - rect.bottom;
    }

    public interface OnKeyboardHeightChangeListener {
        void onKeyboardHeightChange(int keyboardHeight);
    }
}

2) Let your activity be full screen:

activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);

3) Listen for keyboard height changes and add bottom padding for your view:

View rootView = activity.findViewById(R.id.root); // your root view or any other you want to resize
KeyboardHeightHelper effectiveHeightHelper = new KeyboardHeightHelper(
        activity, 
        rootView,
        keyboardHeight -> rootView.setPadding(0, 0, 0, keyboardHeight));

So, each time keyboard will appear on the screen - bottom padding for your view will change, and content will be rearranged.

0
4

I tried Joseph Johnson's class, and it worked, but didn't quite meet my needs. Rather than emulating android:windowSoftInputMode="adjustResize", I needed to emulate android:windowSoftInputMode="adjustPan".

I am using this for a full screen webview. To pan the content view to the correct position, I need to use a javascript interface which provides details on the position of the page element which has focus and thus is receiving the keyboard input. I have omitted those details, but provided my rewrite of Joseph Johnson's class. It will provide a very solid base for you to implement a custom pan vs. his resize.

package some.package.name;

import some.package.name.JavaScriptObject;

import android.app.Activity;
import android.graphics.Rect;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout;

//-------------------------------------------------------
// ActivityPanner Class
//
// Convenience class to handle Activity attributes bug.
// Use this class instead of windowSoftInputMode="adjustPan".
//
// To implement, call enable() and pass a reference
// to an Activity which already has its content view set.
// Example:
//      setContentView( R.layout.someview );
//      ActivityPanner.enable( this );
//-------------------------------------------------------
//
// Notes:
//
// The standard method for handling screen panning
// when the virtual keyboard appears is to set an activity
// attribute in the manifest.
// Example:
// <activity
//      ...
//      android:windowSoftInputMode="adjustPan"
//      ... >
// Unfortunately, this is ignored when using the fullscreen attribute:
//      android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
//
//-------------------------------------------------------
public class ActivityPanner {

    private View contentView_;
    private int priorVisibleHeight_;

    public static void enable( Activity activity ) {
        new ActivityPanner( activity );
    }

    private ActivityPanner( Activity activity ) {
        FrameLayout content = (FrameLayout)
            activity.findViewById( android.R.id.content );
        contentView_ = content.getChildAt( 0 );
        contentView_.getViewTreeObserver().addOnGlobalLayoutListener(
            new ViewTreeObserver.OnGlobalLayoutListener() {
                public void onGlobalLayout() { panAsNeeded(); }
        });
    }

    private void panAsNeeded() {

        // Get current visible height
        int currentVisibleHeight = visibleHeight();

        // Determine if visible height changed
        if( currentVisibleHeight != priorVisibleHeight_ ) {

            // Determine if keyboard visiblity changed
            int screenHeight =
                contentView_.getRootView().getHeight();
            int coveredHeight =
                screenHeight - currentVisibleHeight;
            if( coveredHeight > (screenHeight/4) ) {
                // Keyboard probably just became visible

                // Get the current focus elements top & bottom
                // using a ratio to convert the values
                // to the native scale.
                float ratio = (float) screenHeight / viewPortHeight();
                int elTop = focusElementTop( ratio );
                int elBottom = focusElementBottom( ratio );

                // Determine the amount of the focus element covered
                // by the keyboard
                int elPixelsCovered = elBottom - currentVisibleHeight;

                // If any amount is covered
                if( elPixelsCovered > 0 ) {

                    // Pan by the amount of coverage
                    int panUpPixels = elPixelsCovered;

                    // Prevent panning so much the top of the element
                    // becomes hidden
                    panUpPixels = ( panUpPixels > elTop ?
                                    elTop : panUpPixels );

                    // Prevent panning more than the keyboard height
                    // (which produces an empty gap in the screen)
                    panUpPixels = ( panUpPixels > coveredHeight ?
                                    coveredHeight : panUpPixels );

                    // Pan up
                    contentView_.setY( -panUpPixels );
                }
            }
            else {
                // Keyboard probably just became hidden

                // Reset pan
                contentView_.setY( 0 );
            }

            // Save usabale height for the next comparison
            priorVisibleHeight_ = currentVisibleHeight;
        }
    }

    private int visibleHeight() {
        Rect r = new Rect();
        contentView_.getWindowVisibleDisplayFrame( r );
        return r.bottom - r.top;
    }

    // Customize this as needed...
    private int viewPortHeight() { return JavaScriptObject.viewPortHeight(); }
    private int focusElementTop( final float ratio ) {
        return (int) (ratio * JavaScriptObject.focusElementTop());
    }
    private int focusElementBottom( final float ratio ) {
        return (int) (ratio * JavaScriptObject.focusElementBottom());
    }

}
2
  • seems to be what i need, could you please add an complete sample? thanks for your work!
    – vilicvane
    Jan 28, 2015 at 8:25
  • I wasn't looking to post an entire project. What I've provided will bring you a very long way though towards a perfectly working solution. What you need to define yourself: Create a "JavaScriptObject" class and inject it into your webview as a js interface (Check the webview documentation for that). There's a good chance you've already done that if writing something that uses a webview in a comprehensive manner. Add JavaScript in the webview to listen for focus events and to feed data into your JavaScriptObject class about the focus element positioning.
    – BuvinJ
    Mar 7, 2016 at 18:17
2

Indeed the soft keyboard appearance doesn't seem to affect the Activity in any way no matter what windowSoftInputMode I select in the FullScreen mode.

Though I couldn't find much documentation on this property, I think that the FullScreen mode was designed for gaming application which do not require much use of the soft keyboard. If yours is an Activity which requires user interaction through soft keyboard, please reconsider using a non-FullScreen theme. You could turn off the TitleBar using a NoTitleBar theme. Why would you want to hide the notification bar?

2

Just keep as android:windowSoftInputMode="adjustResize". Because it is given to keep only one out of "adjustResize" and "adjustPan"(The window adjustment mode is specified with either adjustResize or adjustPan. It is highly recommended that you always specify one or the other). You can find it out here: http://developer.android.com/resources/articles/on-screen-inputs.html

It works perfectly for me.

4
  • I am not getting any problem...I have tried your XML also. This one also works..m using Os version 2.2 Sep 15, 2011 at 7:38
  • I have tried with full screen mode only...m testing it on my Nexus One and Nexus S....It works. Sep 15, 2011 at 7:55
  • 1
    I have tried with Galaxy S, HTC wildfire, HTC Hero , Motorola Deify and Sony XPeria. Not working on any single device. Sep 15, 2011 at 8:27
  • let us continue this discussion in chat Sep 15, 2011 at 8:36
1

only use android:windowSoftInputMode="adjustResize|stateHidden as you use AdjustPan then it disable the resizing property

4
  • I have used it too....please make you are doing it in full screen mode and on which device are you testing? Sep 20, 2011 at 7:36
  • HTC NEXUS one, ok i hvnt add full screen Sep 20, 2011 at 7:39
  • can you use getWindow().requestFeature(Window.FEATURE_NO_TITLE); onCreate() instead using theme? Sep 20, 2011 at 7:50
  • 12
    the above code is working fine without full screen but adding full screen either from xml or from code ... It is not working...Please read the question carefully. Sep 20, 2011 at 7:58
1

I used Joseph Johnson created AndroidBug5497Workaround class but getting black space between softkeyboard and the view. I referred this link Greg Ennis. After doing some changes to the above this is my final working code.

 public class SignUpActivity extends Activity {

 private RelativeLayout rlRootView; // this is my root layout
 private View rootView;
 private ViewGroup contentContainer;
 private ViewTreeObserver viewTreeObserver;
 private ViewTreeObserver.OnGlobalLayoutListener listener;
 private Rect contentAreaOfWindowBounds = new Rect();
 private FrameLayout.LayoutParams rootViewLayout;
 private int usableHeightPrevious = 0;

 private View mDecorView;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_sign_up);
  mDecorView = getWindow().getDecorView();
  contentContainer =
   (ViewGroup) this.findViewById(android.R.id.content);

  listener = new OnGlobalLayoutListener() {
   @Override
   public void onGlobalLayout() {
    possiblyResizeChildOfContent();
   }
  };

  rootView = contentContainer.getChildAt(0);
  rootViewLayout = (FrameLayout.LayoutParams)
  rootView.getLayoutParams();

  rlRootView = (RelativeLayout) findViewById(R.id.rlRootView);


  rlRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
   @Override
   public void onGlobalLayout() {
    int heightDiff = rlRootView.getRootView().getHeight() - rlRootView.getHeight();
    if (heightDiff > Util.dpToPx(SignUpActivity.this, 200)) {
     // if more than 200 dp, it's probably a keyboard...
     //  Logger.info("Soft Key Board ", "Key board is open");

    } else {
     Logger.info("Soft Key Board ", "Key board is CLOSED");

     hideSystemUI();
    }
   }
  });
 }

 // This snippet hides the system bars.
 protected void hideSystemUI() {
  // Set the IMMERSIVE flag.
  // Set the content to appear under the system bars so that the 
  content
  // doesn't resize when the system bars hide and show.
  mDecorView.setSystemUiVisibility(
   View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
 }
 @Override
 protected void onPause() {
  super.onPause();
  if (viewTreeObserver.isAlive()) {
   viewTreeObserver.removeOnGlobalLayoutListener(listener);
  }
 }

 @Override
 protected void onResume() {
  super.onResume();
  if (viewTreeObserver == null || !viewTreeObserver.isAlive()) {
   viewTreeObserver = rootView.getViewTreeObserver();
  }
  viewTreeObserver.addOnGlobalLayoutListener(listener);
 }

 @Override
 protected void onDestroy() {
  super.onDestroy();
  rootView = null;
  contentContainer = null;
  viewTreeObserver = null;
 }
 private void possiblyResizeChildOfContent() {
  contentContainer.getWindowVisibleDisplayFrame(contentAreaOfWindowBounds);

  int usableHeightNow = contentAreaOfWindowBounds.height();

  if (usableHeightNow != usableHeightPrevious) {
   rootViewLayout.height = usableHeightNow;
   rootView.layout(contentAreaOfWindowBounds.left,
    contentAreaOfWindowBounds.top, contentAreaOfWindowBounds.right, contentAreaOfWindowBounds.bottom);
   rootView.requestLayout();

   usableHeightPrevious = usableHeightNow;
  } else {

   this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
  }
 }
}
1

based on https://stackoverflow.com/a/19494006/1815624 and desire to make it happen...

updated idea


combining answers from

Relevant code:

        if (heightDifference > (usableHeightSansKeyboard / 4)) {

            // keyboard probably just became visible
            frameLayoutParams.height = usableHeightSansKeyboard - heightDifference;
            activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
            activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
        } else {

            // keyboard probably just became hidden
            if(usableHeightPrevious != 0) {
                frameLayoutParams.height = usableHeightSansKeyboard;
                activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
                activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);

            }

Full Source at https://github.com/CrandellWS/AndroidBug5497Workaround/blob/master/AndroidBug5497Workaround.java

old idea

Create a static value of the containers height before opening the keyboard Set the container height based on usableHeightSansKeyboard - heightDifference when the keyboard opens and set it back to the saved value when it closes

if (heightDifference > (usableHeightSansKeyboard / 4)) {
                // keyboard probably just became visible
                frameLayoutParams.height = usableHeightSansKeyboard - heightDifference;
                int mStatusHeight = getStatusBarHeight();
                frameLayoutParams.topMargin = mStatusHeight;
                ((MainActivity)activity).setMyMainHeight(usableHeightSansKeyboard - heightDifference);

                if(BuildConfig.DEBUG){
                    Log.v("aBug5497", "keyboard probably just became visible");
                }
            } else {
                // keyboard probably just became hidden
                if(usableHeightPrevious != 0) {
                    frameLayoutParams.height = usableHeightSansKeyboard;
                    ((MainActivity)activity).setMyMainHeight();    
                }
                frameLayoutParams.topMargin = 0;

                if(BuildConfig.DEBUG){
                    Log.v("aBug5497", "keyboard probably just became hidden");
                }
            }

Methods in MainActivity

public void setMyMainHeight(final int myMainHeight) {

    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            ConstraintLayout.LayoutParams rLparams =  (ConstraintLayout.LayoutParams) myContainer.getLayoutParams();
            rLparams.height = myMainHeight;

            myContainer.setLayoutParams(rLparams);
        }

    });

}

int mainHeight = 0;
public void setMyMainHeight() {

    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            ConstraintLayout.LayoutParams rLparams =  (ConstraintLayout.LayoutParams) myContainer.getLayoutParams();
            rLparams.height = mainHeight;

            myContainer.setLayoutParams(rLparams);
        }

    });

}

Example Container XML

<android.support.constraint.ConstraintLayout
    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.support.constraint.ConstraintLayout
            android:id="@+id/my_container"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            app:layout_constraintHeight_percent=".8">

similarly margins can be added if needed...

Another consideration is use padding an example of this can be found at:

https://github.com/mikepenz/MaterialDrawer/issues/95#issuecomment-80519589

1
private void resizeWindowOnKeyboardVisible() {
            RelativeLayout rootLayout;
            rootLayout = findViewById(R.id.rootLayout);
            this.getWindow().getDecorView().getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
    
                ViewGroup.LayoutParams layoutParams = rootLayout.getLayoutParams();
                int height ;
    
                @Override
                public void onGlobalLayout() {
                    Rect r = new Rect();
                    getWindow().getDecorView().getWindowVisibleDisplayFrame(r);
                    int screenHeight = rootLayout.getContext().getResources().getDisplayMetrics().heightPixels;
                    int heightDiff = screenHeight - r.bottom;
    
                    if (heightDiff > screenHeight*0.15)
                    {
                        height = screenHeight - heightDiff;
                        layoutParams.height=height;
                        rootLayout.setLayoutParams(layoutParams);
                    }else{
                        height=ViewGroup.LayoutParams.MATCH_PARENT;
                        if( height!=layoutParams.height) {
                            layoutParams.height = height;
                            rootLayout.setLayoutParams(layoutParams);
                        }
                    }
                }
            });
        }

Using android:windowSoftInputMode="adjustResize|stateHidden might not work in all cases and also android:fitsSystemWindows="true doesn't help when you use SYSTEM_UI_FLAG_FULLSCREEN tags. To make view/window/webview adjustable when Keyboard visible do the following things.

  • Use RelativeLayout as root layout.
  • Declare the above method resizeWindowOnKeyboardVisible() in an activity & call it after setContentView() in onCreate() method.

It works in Android 11 (API 30) also.

1

Based on @Sdghasemi's solution, here's my Kotlin code, without the deprecated insets.getSystemWindowInsetBottom(). Also I added a padding animation to make the keyboard opening smoother.

val rootLayout = findViewById<RelativeLayout>(R.id.your_root_layout)      
ViewCompat.setOnApplyWindowInsetsListener(rootLayout) { v, insets ->
    val animator = ValueAnimator.ofInt(0, insets.getInsets(WindowInsetsCompat.Type.ime()).bottom))
    animator.addUpdateListener { 
        valueAnimator -> v.setPadding(0, 0, 0, valueAnimator.animatedValue as? Int ?: 0) 
    }
    animator.duration = 200
    animator.start()
    insets
}

Call it from the onCreate() method of your Activity. In my case, this snippet works better than setting android:windowSoftInputMode="adjustPan" in the AndroidManifest.xml

0
0

You want the bottom bar to stick to the bottom of the view, but when the keyboard is displayed, they should move up to be placed above the keyboard, right?

You can try this code snippet:

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    ...>

    <RelativeLayout
        android:id="@+id/RelativeLayoutTopBar"
    ...>
    </RelativeLayout>

    <LinearLayout
        android:id="@+id/LinearLayoutBottomBar"
        android:layout_alignParentBottom = true
        ...>
    </LinearLayout>

    <LinearLayout
    android:layout_width="fill_parent"
    android:layout_height="390dp"
    android:orientation="vertical" 
    android:layout_above="@+id/LinearLayoutBottomBar"
    android:layout_below="@+id/RelativeLayoutTopBar"> 

    <ScrollView 
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:layout_marginBottom="10dp"
        android:id="@+id/ScrollViewBackground">

            ...

        </ScrollView>
     </LinearLayout>
  </RelativeLayout>

The BottomBar will stick to the bottom of the view and the LinearLayout containing the ScrollView will take what's left of the view after the top/bottom bar and the keyboard are displayed. Let me know if it works for you as well.

5
  • 1
    Very strange as it worked in my apps several times. By the way, RelativeLayout has no orientation so you can delete these attributes in your code. I just recognized I could have cut down the code snippet to the line: android:layout_below="@+id/scoringContainerView" which you have to add to your ScrollView
    – banzai86
    Sep 20, 2011 at 14:26
  • Fullscreen? Do you mean without a layout at the top?
    – banzai86
    Sep 20, 2011 at 14:33
  • no ..... I mean no status bar which show battery life, connectivity for the device etc.... Sep 20, 2011 at 14:34
  • no, the statusbar is visible in my app. can you try changing the order of your layouts, meaning that you put the code for your layout with the buttons above the other code and then try again? maybe you have to define them first in order to use the layout_below
    – banzai86
    Sep 20, 2011 at 14:38
  • 1
    please read the question carefully......I have mentioned I am having trouble with FullScreen mode...... Sep 20, 2011 at 14:39
0

Thank you Joseph for your answer. However, in the method possiblyResizeChildOfContent(), the portion

else {
            // keyboard probably just became hidden
            frameLayoutParams.height = usableHeightSansKeyboard;
        }

was not working for me, as the lower portion of view became hidden. So I had to take a global variable restoreHeight, and in the constructor, I inserted the last line

restoreHeight = frameLayoutParams.height;

and then I replaced the former mentioned part with

else {
            // keyboard probably just became hidden
            frameLayoutParams.height = restoreHeight;
        }

But I have no idea why your code didn't work for me. It would be of great help, if someone can shed light on this.

0

I was only using full screen mode to hide the status bar. However, I want the app to resize when keyboard is shown. All of the other solutions (likely due to age of post) were complicated or not possible for my use (want to avoid change Java code for sack of PhoneGap Build).

Instead of using Full screen, I modified my configure for Android to be non-fullscreen:

            <preference name="fullscreen" value="false" />

And added the cordova-plugin-statusbar, via command line:

cordova plugin add cordova-plugin-statusbar

When app has loaded, I simple call a method on the plugin to hide itself, like:

    if (window.cordova && window.cordova.platformId == 'android' && window.StatusBar)
        window.StatusBar.hide();

This works like a charm. Only real downside is that the status bar is breifly visible while the app loads. For my needs, that wasn't an issue.

0

I have tried out all the possible answers from stackOverflow, finally i solved after a week Long search . I have used the coordinate layout and i changed this with linearLayout and my problem is fixed. I dont know possibly the coordinate layout has bugs or anything my mistake.

0

I tried many solutions include Joseph Johnson's and Johan Stuyts's. But as a result I got a white space between content and keyboard on some devices (like Lenovo s820) in all cases. So I made some changes to their codes and finally got working solution.

My idea based on adding margin to top of content when keyboard is showing.

contentContainer.getWindowVisibleDisplayFrame(contentAreaOfWindowBounds);
    int usableHeightNow = contentAreaOfWindowBounds.height();

    if (usableHeightNow != usableHeightPrevious) {

        int difference = usableHeightNow - usableHeightPrevious;

        if (difference < 0 && difference < -150) {
            keyboardShowed = true;
            rootViewLayout.topMargin -= difference + 30;
            rootViewLayout.bottomMargin += 30;
        }
        else if (difference < 0 && difference > -150){
            rootViewLayout.topMargin -= difference + 30;
        }
        else if (difference > 0 && difference > 150) {
            keyboardShowed = false;
            rootViewLayout.topMargin = 0;
            rootViewLayout.bottomMargin = 0;
        }

        rootView.requestLayout();

        Log.e("Bug Workaround", "Difference: " + difference);

        usableHeightPrevious = usableHeightNow;
}

As you can see, I add 30 px to difference because there is a small white space between top of the screen and content zone with margin. And I dont know whence it appears so I decided just make margins smaller and now it works exactly how I needed.

0
0

Today not working adjustResize on full screen issue is actual for android sdk.

From answers i found:
the solution - but solution has this showing on picture issue :

Than i found the solution and remove the one unnecessary action:

this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);

So, see my fixed solution code on Kotlin:

class AndroidBug5497Workaround constructor(val activity: Activity) {

    private val content = activity.findViewById<View>(android.R.id.content) as FrameLayout

    private val mChildOfContent = content.getChildAt(0)
    private var usableHeightPrevious: Int = 0
    private val contentContainer = activity.findViewById(android.R.id.content) as ViewGroup
    private val rootView = contentContainer.getChildAt(0)
    private val rootViewLayout = rootView.layoutParams as FrameLayout.LayoutParams

    private val listener = {
        possiblyResizeChildOfContent()
    }

    fun addListener() {
        mChildOfContent.apply {
            viewTreeObserver.addOnGlobalLayoutListener(listener)

        }
    }

    fun removeListener() {
        mChildOfContent.apply {
            viewTreeObserver.removeOnGlobalLayoutListener(listener)
        }
    }

    private fun possiblyResizeChildOfContent() {
        val contentAreaOfWindowBounds = Rect()
        mChildOfContent.getWindowVisibleDisplayFrame(contentAreaOfWindowBounds)
        val usableHeightNow = contentAreaOfWindowBounds.height()

        if (usableHeightNow != usableHeightPrevious) {
            rootViewLayout.height = usableHeightNow
            rootView.layout(contentAreaOfWindowBounds.left,
                    contentAreaOfWindowBounds.top, contentAreaOfWindowBounds.right, contentAreaOfWindowBounds.bottom);
            mChildOfContent.requestLayout()
            usableHeightPrevious = usableHeightNow
        }
    }
}

My bug fixing implement code:

 class LeaveDetailActivity : BaseActivity(){

    private val keyBoardBugWorkaround by lazy {
        AndroidBug5497Workaround(this)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

    }

    override fun onResume() {
        keyBoardBugWorkaround.addListener()
        super.onResume()
    }

    override fun onPause() {
        keyBoardBugWorkaround.removeListener()
        super.onPause()
    }
}
0

There is another way, without creating own helper classes or functions that calculate the height of the screen. Instead use ViewCompat.setOnApplyWindowInsetsListener. With the listener you can check if the keyboard is open and set the bottom padding based on the keyboard height.

// the root view of your webview, e.g FrameLayout or LinearLayout
    rootView = view.findViewById(R.id.whatever);
    
    ViewCompat.setOnApplyWindowInsetsListener(rootView, (webView, insets) -> {
        
        // checks if keyboard is visible, the Type.ime() stands for Input Method
        boolean isKeyboardVisible = insets.isVisible(WindowInsetsCompat.Type.ime());
        
        // get the keyboard height and use the height as bottom padding for your view
        int bottomKeyboardPadding = insets.getInsets(WindowInsetsCompat.Type.ime()).bottom;

        
        if (isKeyboardVisible) { webView.setPadding(0, 0, 0, bottomKeyboardPadding); }
        else { webView.setPadding(0, 0, 0, 0); }

        return insets;
    });
0

If you want to really support full screen with soft input:

private fun View.setStatusBarTransparent() {
    [email protected] {
        window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
        window.statusBarColor = ContextCompat.getColor(this, R.color.transparent)
        [email protected] = true
        WindowCompat.setDecorFitsSystemWindows(window, false)
        ViewCompat.setOnApplyWindowInsetsListener(this@setStatusBarTransparent) { root, windowInset ->
            val inset = windowInset.getInsets(WindowInsetsCompat.Type.systemBars())
            val inset2 = windowInset.getInsets(WindowInsetsCompat.Type.ime())
            root.updateLayoutParams<ViewGroup.MarginLayoutParams> {
                leftMargin = inset.left
                bottomMargin = maxOf(inset.bottom, inset2.bottom)
                rightMargin = inset.right
            }
            WindowInsetsCompat.CONSUMED
        }
    }
}
1
  • How to use ?...
    – ΓDΛ
    Oct 28, 2023 at 9:47
-1

Don't use:

getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);

because works bad. Instead of that, use:

fun setFullScreen(fullScreen: Boolean) {
        val decorView = getWindow().getDecorView()
        val uiOptions : Int
        if(fullScreen){
            uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN // this hide statusBar
            toolbar.visibility = View.GONE // if you use toolbar
            tabs.visibility = View.GONE // if you use tabLayout
        } else {
            uiOptions = View.SYSTEM_UI_FLAG_VISIBLE // this show statusBar
            toolbar.visibility = View.VISIBLE
            tabs.visibility = View.VISIBLE
        }
        decorView.setSystemUiVisibility(uiOptions)
    }
-2

In my case, this issue started happening once I added Crosswalk to my Cordova application. My app is not used in fullscreen and android:windowSoftInputMode="adjustPan".

I already had the ionic keyboard plugin in the application, so detecting if the keyboard was up or down was easy thanks to it:

// Listen for events to when the keyboard is opened and closed
window.addEventListener("native.keyboardshow", keyboardUp, false);
window.addEventListener('native.keyboardhide', keyboardDown, false);

function keyboardUp()
{
    $('html').addClass('keyboardUp');
}

function keyboardDown()
{
    $('html').removeClass('keyboardUp');
}

I tried all of the fixes above but the simple line that ended up doing it for me was this bit of css:

&.keyboardUp {
        overflow-y: scroll;
}

Hope this saves you the few days I spent on this. :)

2
  • I'm using crosswalk with cordova as well with android:windowSoftInputMode="adjustPan". However, it's not working. I see that the class is getting added to the html element, but the css has no effect on the screen. Is there some other setting you have that allows for the screen to move?
    – darewreck
    Oct 17, 2016 at 21:11
  • I have to set the add transform:translateY(0px) for it to work. However, the scrolling doesn't work at all. Any ideas?
    – darewreck
    Oct 17, 2016 at 21:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.