preface

We want to achieve a floating input bar on the soft keyboard (that is, a floating bar), encountered a lot of problems in the process, looked up some online articles, the results found that many are wrong, take some detdettions, here one by one record.

Suspension bar

Implementing the floating bar is simple

chatInputPanel.setVisibility(View.VISIBLE);
chatInputEt.setFocusable(true);
chatInputEt.setFocusableInTouchMode(true);
chatInputEt.requestFocus();
InputMethodManager inputManager = (InputMethodManager)chatInputEt.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
inputManager.showSoftInput(chatInputEt, 0);
Copy the code

ChatInputPanel is the entire layout of the floating bar. MChatPanelContent is the actual part of the floating bar. ChatInputEt is the EditText of the floating bar.

Here chatInputPanel is full screen (click on mChatPanelContent to hide the keyboard), mChatPanelContent is at the bottom of its bottom, hidden by default (INVISIBLE).

Soft keyboard full screen in landscape

In landscape mode, Android’s soft keyboard is displayed in full screen by default, making it impossible to hover. So you need to cancel the full screen display

Using Android in EditText :imeOptinos allows you to do some interface Settings for android’s built-in soft keyboard

  • Android :imeOptions=”flagNoExtractUi

  • Android :imeOptions=”actionNone” // There is no prompt on the right side of the input box

  • Android :imeOptions=”actionGo” // lower right button content is’ start ‘

  • Android :imeOptions=”actionSearch” // Lower right button for magnifying glass image, search

  • Android :imeOptions=”actionSend” // lower right button content ‘send’

  • Android :imeOptions=”actionNext” // lower right button content is’ next ‘

  • Android :imeOptions=”actionDone” // bottom right button content is’ done ‘

So we set Android :imeOptions=”flagNoExtractUi” for the EditText to not display in full screen in landscape. At the same time, you might add a listener to EditText that captures the listener event when the user clicks the button in the lower-right corner of the soft keyboard for processing.

editText.setOnEditorActionListener(new OnEditorActionListener() {   

        @Override  

        public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {   

            Toast.makeText(MainActivity.this."text2", Toast.LENGTH_SHORT).show();   

            return false; }});Copy the code

Listen to the soft keyboard (this method is not reliable, abandoned, the following have reliable)

Note: this is a wrong method on the Internet, so specially out to say, not interested in directly go to see (3) can be.

The display is ok, but when the soft keyboard is hidden, it requires the hover bar to be synchronously hidden.

There is no API for listening to soft keyboard collapse, so we have to implement it ourselves.

chatInputPanel.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout(a) {
        if(chatInputPanel.getBottom() > container.getRootView().getHeight() / 2){
            chatInputPanel.setVisibility(View.INVISIBLE);
        }
        else{ chatInputPanel.setVisibility(View.VISIBLE); }}});Copy the code

Monitor chatInputPanel layout changes, hide when the bottom is more than half the height of rootView, display otherwise.

Since our function is landscape, the bottom of the chatInputPanel must be less than half the height (screen width) of the RootView because it is suspended on the keyboard when the keyboard bounts up.

When the keyboard is closed, the chatInputPanel goes back to the bottom (set at the bottom of the parent layout), so the bottom must be more than halfway down.

This method is unreliable, and redrawing will cause onGlobalLayout to execute frequently. Although you can add a time control, it is not recommended to use this method to listen to the soft keyboard. Let’s look at another method.

Reliable method of monitoring soft keyboard

Why is the above method not considered, because displaying FLAG_FULLSCREEN causes problems

The FLAG_FULLSCREEN property is used when we need to show a hidden notification bar in full screen

getActivity().getWindow().setFlags(
        WindowManager.LayoutParams.FLAG_FULLSCREEN,
        WindowManager.LayoutParams.FLAG_FULLSCREEN);
Copy the code

Chatinputpanel.getbottom () does not change, but we can tell by this change.

It hasn’t changed because of how Android handles FLAG_FULLSCREEN in full screen, and there are a lot of issues with the soft keyboard when it’s full screen, and there are a lot of them on this website.

How to solve it?

Let’s listen in on the soft keyboard in a different way

getActivity().getWindow().getDecorView().getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout(a) {
        Rect rect = new Rect();
        rootView.getWindowVisibleDisplayFrame(rect);
        int rootHeight=rootView.getRootView().getHeight();

        int displayHeight=rect.height();
        int diffHeight=rootHeight-displayHeight;
        if(diffHeight==0) {// Put the keyboard away
            chatInputPanel.setVisibility(View.INVISIBLE);
        }else{
            // The keyboard pops upchatInputPanel.setVisibility(View.VISIBLE); }}});Copy the code

By listening for changes in the content layout of the root layout, this method is by far the most reliable.

However, there is a small problem: in full screen, the keyboard covers a small part of the bottom of the hover bar. What about this?

Ultimate levitation mode

The above fixed the monitoring problem of the soft keyboard, but the floating bar always covered part of the full screen, what should I do?

In fact, there is another problem, when the keyboard is displayed, the overall layout of the app is pushed up, which causes some components to shrink and so on.

We need to solve this problem first, so that the overall layout of the app stays still and the keyboard is covered on it, which needs to be set manually before the keyboard is unpressed, as follows:

mChatInput.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        DisplayMetrics metric = new DisplayMetrics();
        getActivity().getWindowManager().getDefaultDisplay().getMetrics(metric);
        chatInputPanel.setY(-metric.heightPixels);// Resolve the first possible push up issue
        
        chatInputEt.setFocusable(true);
        chatInputEt.setFocusableInTouchMode(true);
        chatInputEt.requestFocus();
        InputMethodManager inputManager = (InputMethodManager)chatInputEt.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
        inputManager.showSoftInput(chatInputEt, 0); }});Copy the code

So moved to the top of above, the suspension bar will not appear on the push of the (guess is associated with the mechanism of the keyboard, because the keyboard pops up if only obscured the input component with a focus to readjust window, we will be suspended window on top, how to don’t keep out the keyboard focus EditText, so will not resize the window).

But such suspension column has been out of sight, and we can see here to remove chatInputPanel. SetVisibility (the VISIBLE). Code, so how to display?

As mentioned above, we can use OnGlobalLayoutListener to monitor the keyboard, and we can display it here. Meanwhile, we can optimize the display position, calculate how much the display area of the window moves up, and let chatInputPanel also move up the corresponding position.

private int mLastHeight = 0;
getActivity().getWindow().getDecorView().getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout(a) {
        Rect rect = new Rect();
        getActivity().getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);
        int height = rect.height();
        int rawHeight = getResources().getDisplayMetrics().heightPixels - rect.top;
        if (height == mLastHeight)
            return;
            
        if (height < rawHeight) {
            UiThreadHandler.postDelayed(new Runnable() {
                @Override
                public void run(a) { chatInputPanel.setVisibility(View.VISIBLE); chatInputPanel.setTranslationY(-(rawHeight - height)); }},200);
        } else {
            UiThreadHandler.postDelayed(new Runnable() {
                @Override
                public void run(a) { chatInputPanel.setVisibility(View.GONE); }},100); } mLastHeight = height; }});Copy the code

You can see that you get the display height of the current window and the actual height of the screen (the window part).

Then determine whether the display area of the window has changed, if no change is not processed.

If there is a change, then determine whether it has become larger or smaller.

If it gets smaller

The chatInputPanel is displayed when the keyboard is up and the translationY is set to -(rawHeight height).

The bottom of the chatInputPanel is aligned with the bottom of the screen. SetY is the same as setTranslationY. The bottom of the chatInputPanel is aligned with the bottom of the screen.

public void setY(float y) {
    setTranslationY(y - mTop);
}
Copy the code

If you want to be above the keyboard, you need to move one keyboard height up from the bottom, the keyboard height is rawheight-height, so when you move up, you set the translationY to -(Rawheight-height).

If I get bigger

Hide the chatInputPanel from the keyboard.

This not only solves the problem of pushing up the window, but also solves the problem of blocking part of the floating bar on the soft keyboard, because the position of the floating bar is obtained through calculation, not through the soft keyboard to adjust the layout and change the position.

The final code

Finally, I want to form this into an independent component, which can be used directly. During the process of writing, I found many problems. After solving all the problems, I found that the code is different from the above code, but the idea is the same, but the details have been adjusted, such as obtaining the keyboard height.

Follow the public account: BennuCTech, get more dry goods