Wednesday, May 24, 2017

Get the height of soft keyboard of device


I. AdjustResize and AdjustPan

You can get the height of soft keyboard that use windowSoftInputMode="adjustResize|adjustPan"   by Viewtree Observer and global layout listener, just try below mentioned steps
    1. Get the root view of your layout
    2. Get the Viewtree observer for this root, and add a global layout listener on top of this.
Now whenever soft keyboard is displayed android will re-size your screen and you will receive call on your listener. That's it only thing you now need to do is calculate difference between height which your root view has after re-size and original size. If difference is more then 150 consider this as a keyboard has been inflated.

In Activity class :
final LinearLayout ll_main = (LinearLayout) findViewById(R.id.ll_main);
final Window mRootWindow = getWindow();
        ll_main.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener(){
            public void onGlobalLayout(){
                int screenHeight = ll_main.getRootView().getHeight();
                Rect r = new Rect();
                View view = mRootWindow.getDecorView();
                view.getWindowVisibleDisplayFrame(r);

                int keyBoardHeight = screenHeight - r.bottom;
            }
        });

II. AdjustNothing

If you want to get the height of soft keyboard that use windowSoftInputMode="adjustNothing"

1. popupwindow.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/popuplayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/transparent"
    android:orientation="horizontal"/>

2. activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/activitylayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

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

        <TextView
      android:id="@+id/info_label"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="10dp"
            android:textColor="@android:color/black"
            android:textSize="16dp"
            android:text="@string/info">

        </TextView>

        <EditText
      android:id="@+id/input_name"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="10dp"
            >
        </EditText>
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dp"
            android:orientation="horizontal">

            <TextView
          android:id="@+id/height_label"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginRight="10dp"
                android:textColor="@android:color/black"
                android:textSize="16dp"
                android:text="@string/height">

            </TextView>

            <TextView
          android:id="@+id/height_text"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:textColor="@android:color/black"
                android:textSize="16dp"
                android:text="0">

            </TextView>

        </LinearLayout>

    </LinearLayout>

    <View 
  android:id="@+id/keyboard"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_alignParentBottom="true"
        android:background="#0000ff"/>
</RelativeLayout>


3. KeyboardHeightObserver.java

public interface KeyboardHeightObserver {

    /** 
     * Called when the keyboard height has changed, 0 means keyboard is closed,
     * >= 1 means keyboard is opened.
     * 
     * @param height        The height of the keyboard in pixels
     * @param orientation   The orientation either: Configuration.ORIENTATION_PORTRAIT or 
     *                      Configuration.ORIENTATION_LANDSCAPE
     */
    void onKeyboardHeightChanged(int height, int orientation);
}

4. KeyboardHeightProvider.java

/**
 * The keyboard height provider, this class uses a PopupWindow
 * to calculate the window height when the floating keyboard is opened and closed. 
 */
public class KeyboardHeightProvider extends PopupWindow {

    /** The tag for logging purposes */
    private final static String TAG = "sample_KeyboardHeightProvider";

    /** The keyboard height observer */
    private KeyboardHeightObserver observer;

    /** The cached landscape height of the keyboard */
    private int keyboardLandscapeHeight;

    /** The cached portrait height of the keyboard */
    private int keyboardPortraitHeight;

    /** The view that is used to calculate the keyboard height */
    private View popupView;

    /** The parent view */
    private View parentView;

    /** The root activity_main that uses this KeyboardHeightProvider */
    private Activity activity;

    /** 
     * Construct a new KeyboardHeightProvider
     * 
     * @param activity The parent activity_main
     */
    public KeyboardHeightProvider(Activity activity) {
  super(activity);
        this.activity = activity;

        LayoutInflater inflator = (LayoutInflater) activity.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
        this.popupView = inflator.inflate(R.layout.popupwindow, null, false);
        setContentView(popupView);

        setSoftInputMode(LayoutParams.SOFT_INPUT_ADJUST_RESIZE | LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
        setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);

        parentView = activity.findViewById(android.R.id.content);

        setWidth(0);
        setHeight(LayoutParams.MATCH_PARENT);

        popupView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {

                @Override
                public void onGlobalLayout() {
                    if (popupView != null) {
                        handleOnGlobalLayout();
                    }
                }
            });
    }

    /**
     * Start the KeyboardHeightProvider, this must be called after the onResume of the Activity.
     * PopupWindows are not allowed to be registered before the onResume has finished
     * of the Activity.
     */
    public void start() {

        if (!isShowing() && parentView.getWindowToken() != null) {
            setBackgroundDrawable(new ColorDrawable(0));
            showAtLocation(parentView, Gravity.NO_GRAVITY, 0, 0);
        }
    }

    /**
     * Close the keyboard height provider, 
     * this provider will not be used anymore.
     */
    public void close() {
        this.observer = null;
        dismiss();
    }

    /** 
     * Set the keyboard height observer to this provider. The 
     * observer will be notified when the keyboard height has changed. 
     * For example when the keyboard is opened or closed.
     * 
     * @param observer The observer to be added to this provider.
     */
    public void setKeyboardHeightObserver(KeyboardHeightObserver observer) {
        this.observer = observer;
    }
   
    /**
     * Get the screen orientation
     *
     * @return the screen orientation
     */
    private int getScreenOrientation() {
        return activity.getResources().getConfiguration().orientation;
    }

    /**
     * Popup window itself is as big as the window of the Activity. 
     * The keyboard can then be calculated by extracting the popup view bottom 
     * from the activity_main window height.
     */
    private void handleOnGlobalLayout() {

        Point screenSize = new Point();
        activity.getWindowManager().getDefaultDisplay().getSize(screenSize);

        Rect rect = new Rect();
        popupView.getWindowVisibleDisplayFrame(rect);

        // REMIND, you may like to change this using the fullscreen size of the phone
        // and also using the status bar and navigation bar heights of the phone to calculate
        // the keyboard height. But this worked fine on a Nexus.
        int orientation = getScreenOrientation();
        int keyboardHeight = screenSize.y - rect.bottom;
        
        if (keyboardHeight == 0) {
            notifyKeyboardHeightChanged(0, orientation);
        }
        else if (orientation == Configuration.ORIENTATION_PORTRAIT) {
            this.keyboardPortraitHeight = keyboardHeight; 
            notifyKeyboardHeightChanged(keyboardPortraitHeight, orientation);
        } 
        else {
            this.keyboardLandscapeHeight = keyboardHeight; 
            notifyKeyboardHeightChanged(keyboardLandscapeHeight, orientation);
        }
    }

    /**
     *
     */
    private void notifyKeyboardHeightChanged(int height, int orientation) {
        if (observer != null) {
            observer.onKeyboardHeightChanged(height, orientation);
        }
    }
}

5. MainActivity.java

/**
 * MainActivity that initialises the keyboardheight 
 * provider and observer. 
 */
public final class MainActivity extends AppCompatActivity implements KeyboardHeightObserver {

    /** Tag for logging */
    private final static String TAG = "sample_MainActivity";

    /** The keyboard height provider */
    private KeyboardHeightProvider keyboardHeightProvider;

    /**
     * {@inheritDoc}
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        keyboardHeightProvider = new KeyboardHeightProvider(this);

        // make sure to start the keyboard height provider after the onResume
        // of this activity_main. This is because a popup window must be initialised
        // and attached to the activity_main root view.
        View view = findViewById(R.id.activitylayout);
        view.post(new Runnable() {
                public void run() {
                    keyboardHeightProvider.start();
                }
            });
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void onPause() {
        super.onPause();
        keyboardHeightProvider.setKeyboardHeightObserver(null);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void onResume() {
        super.onResume();
        keyboardHeightProvider.setKeyboardHeightObserver(this);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void onDestroy() {
        super.onDestroy();
        keyboardHeightProvider.close();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void onKeyboardHeightChanged(int height, int orientation) {

        String or = orientation == Configuration.ORIENTATION_PORTRAIT ? "portrait" : "landscape";
        Log.i(TAG, "onKeyboardHeightChanged in pixels: " + height + " " + or);

        TextView tv = (TextView)findViewById(R.id.height_text);
        tv.setText(Integer.toString(height) + " " + or);

        // color the keyboard height view, this will stay when you close the keyboard
        View view = findViewById(R.id.keyboard);
        RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams)view .getLayoutParams();
        params.height = height;
    }
}

2 comments

Great article, keep up the good work!

Amazing! I was looking for the second solution for so long! Thank you!


EmoticonEmoticon