I've got a working solution that I'd like to share.
First off, there is no way to get the soft keyboard height out of the libgdx api. You have to write platform specific code. Interfacing with platform specific code is rather simple - don't worry! Read this guide from the official libgdx wiki.
The following code is native android code, that should be placed in the libgdx android gradle module:
import android.graphics.Rect;
import android.view.View;
import android.view.ViewTreeObserver;
import android.view.Window;
import com.badlogic.gdx.backends.android.AndroidApplication;
/**
* Container for platform-specific android implementation.
*/
public class PlatformSpecificAndroidImpl implements PlatformSpecificService {
private AndroidApplication androidApplication;
private AndroidGlobalLayoutListener globalLayoutListener;
public PlatformSpecificAndroidImpl(AndroidApplication androidApplication) {
this.androidApplication = androidApplication;
}
/**
* Initialize platform services. This method should be called from the gdx applications "create()" method.
*/
@Override
public void init() {
globalLayoutListener = new AndroidGlobalLayoutListener(androidApplication);
Window window = androidApplication.getWindow();
if (window != null) {
View decorView = window.getDecorView();
if (decorView != null) {
View rootView = decorView.getRootView();
if (rootView != null) {
ViewTreeObserver viewTreeObserver= rootView.getViewTreeObserver();
if (viewTreeObserver != null) {
viewTreeObserver.addOnGlobalLayoutListener(globalLayoutListener);
}
}
}
}
}
/**
* Get the window height that is really usable, subtracting the soft-keyboard if open.
* @return usable window height
*/
@Override
public int getUsableWindowHeight() {
if (globalLayoutListener != null) {
return globalLayoutListener.getHeight();
}
return 0;
}
private static class AndroidGlobalLayoutListener implements ViewTreeObserver.OnGlobalLayoutListener {
private AndroidApplication androidApplication;
private int height;
private AndroidGlobalLayoutListener(AndroidApplication androidApplication) {
this.androidApplication = androidApplication;
}
@Override
public void onGlobalLayout() {
height = 0;
Window window = androidApplication.getWindow();
if (window != null) {
View currentFocus = window.getCurrentFocus();
if (currentFocus != null) {
View rootView = currentFocus.getRootView();
if (rootView != null) {
Rect rect = new Rect();
rootView.getWindowVisibleDisplayFrame(rect);
height = rect.bottom;
}
}
}
}
public int getHeight() {
return height;
}
}
}
From within the libgdx core module you can now call the method getUsableWindowHeight()
via the PlatformSpecificService interface. It returns the display height (in pixels) minus the soft keyboard height.
Why did I use the OnGlobalLayoutListener and not calculate the height directly in the getter method, when it is requested? Well, in my option it is a slightly more elegant solution this way.
There is one more gotcha to be aware of:
Opening the soft keyboard via Gdx.input.setOnscreenKeyboardVisible(true);
involves asynchronous communication. If you happen to call getUsableWindowHeight()
directly after setOnscreenKeyboardVisible, you will still get the full display height, because the keyboard did not yet actually open.