Android programming soft keyboard hidden display example details

  • 2020-11-20 06:13:56
  • OfStack

This paper gives an example to analyze the hidden display method of Android programming soft keyboard. To share for your reference, the details are as follows:

Android is an operating system specially designed for touch screen. When the edit box is clicked, the system automatically pops up a soft keyboard for the user to enter.

So, after the pop-up soft keyboard will inevitably cause the original layout height reduction, so how should the system deal with the reduction of layout? Can we have custom control in the application? These are the main points of this article.

1. Principle of soft keyboard display

What is the essence of software disk? The soft keyboard is actually an Dialog!
InputMethodService creates an Dialog for our input method and sets some of the Window parameters of that Dialog, such as Gravity, so that they can be displayed at the bottom or in full screen. When we click the input box, the system adjusts the active main window to make room for the input method, and then displays the Dialog at the bottom or in full screen.

2. Adjust the active main window

android defines a property, called windowSoftInputMode, that allows programs to control how the active main window is adjusted. We can set Activity in ES25en.xml. Such as: android: windowSoftInputMode = "stateUnchanged | adjustPan"

The optional value of this property has two parts: one is the state control of the soft keyboard, and the other is the adjustment of the active main window. The first part of this article is not discussed. Please refer to the android documentation for yourself.

Mode 1, compression mode

If the value of windowSoftInputMode is set to adjustResize, the Activity main window is always resized to make room for the soft keyboard.

We use 1 section of code to test what the system does when we set this property and pop up the input method.

Rewrite the Layout layout:


public class ResizeLayout extends LinearLayout{ 
  private static int count = 0; 
  public ResizeLayout(Context context, AttributeSet attrs) { 
   super(context, attrs); 
  } 
 @Override 
  protected void onSizeChanged(int w, int h, int oldw, int oldh) {  
   super.onSizeChanged(w, h, oldw, oldh); 
   Log.e("onSizeChanged " + count++, "=>onResize called! w="+w + ",h="+h+",oldw="+oldw+",oldh="+oldh); 
  } 
  @Override 
  protected void onLayout(boolean changed, int l, int t, int r, int b) { 
   super.onLayout(changed, l, t, r, b); 
   Log.e("onLayout " + count++, "=>OnLayout called! l=" + l + ", t=" + t + ",r=" + r + ",b="+b); 
  } 
  @Override 
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 
   super.onMeasure(widthMeasureSpec, heightMeasureSpec); 
   Log.e("onMeasure " + count++, "=>onMeasure called! widthMeasureSpec=" + widthMeasureSpec + ", heightMeasureSpec=" + heightMeasureSpec); 
}

Our layout is set as:


<com.winuxxan.inputMethodTest.ResizeLayout 
  xmlns:android="http://schemas.android.com/apk/res/android" 
  android:id="@+id/root_layout" 
  android:layout_width="fill_parent" 
  android:layout_height="fill_parent" 
  android:orientation="vertical" 
  > 
  <EditText 
   android:layout_width="fill_parent" 
   android:layout_height="wrap_content" 
  /> 
  <LinearLayout 
    android:id="@+id/bottom_layout" 
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent" 
    android:orientation="vertical" 
    android:gravity="bottom">s 
  <TextView  
   android:layout_width="fill_parent" 
   android:layout_height="wrap_content" 
   android:text="@string/hello" 
   android:background="#77777777" 
  /> 
 </LinearLayout> 
</com.winuxxan.inputMethodTest.ResizeLayout>

AndroidManifest. xml Activity setting property: android:windowSoftInputMode = "adjustResize"

Run the program and click the text box to view the debugging information:

E/onMeasure 6(7960): = > onMeasure called! widthMeasureSpec=1073742144, heightMeasureSpec = 1073742024
E/onMeasure 7(7960): = > onMeasure called! widthMeasureSpec=1073742144, heightMeasureSpec = 1073742025
E/onSizeChanged 8(7960): = > onSizeChanged called! w=320,h=201,oldw=320,oldh=377
E/onLayout 9(7960): = > OnLayout called! l=0, t=0,r=320,b=201

As you can see from the debug results, when we click on the text box, the root layout invokes onMeasure, onSizeChanged, and onLayout.

In fact, when set to adjustResize, when the soft keyboard pops up, the main window layout is redone to measure and layout, and on layout, the change in window size is noticed, so onSizeChanged is called.

From the results of the operation, we can also see that TextView, which was originally at the bottom, is jacked to the top of the input method.

Mode 2, translation mode

If the value of windowSoftInputMode is set to adjustPan, the main window of Activity does not resize the screen to make room for the soft keyboard. Instead, the contents of the current window move automatically so that the current focus is never overridden by the keyboard and the user always sees the part of the input. This is generally not expected to be resized, as the user may turn off the soft keyboard in order to interact with the overridden content.

In the above example, we changed the attributes of AndroidManifest.xml: android = "adjustPan"

Rerun and click the text box to view the debugging information:

E/onMeasure 6(8378): = > onMeasure called! widthMeasureSpec=1073742144, heightMeasureSpec=1073742200
E/onMeasure 7(8378): = > onMeasure called! widthMeasureSpec=1073742144, heightMeasureSpec=1073742201
E/onLayout 8(8378): = > OnLayout called! l=0, t=0,r=320,b=377

We can see that the system also redid measrue and layout, but we found that onSizeChanged was not called in the process of layout, which indicates that the size of the original layout did not change before and after the input method was ejected.

From the running results, we can see that the TextView below is not jacked to the top of the input method.

In fact, the mode does not adjust the layout when the input field is not obscured, while the window pans when the input field is about to be obscured. That is, the pattern always keeps the input field visible. The entire window, including the title bar, is moved up to make the text box visible.

Mode 3 Auto mode

When the property windowSoftInputMode is set to adjustUspecified, it is not specified whether the main window of Activity is resized to leave room for the soft keyboard, or whether the contents of the window are made visible by the current focus on the screen. The system will automatically select one of these modes depending on whether the contents of the window have any layout views that can scroll their contents. If there is such a view, the window will be resized, assuming that the contents of the scrolling window will be visible in a smaller area. This is the default behavior for the main window.

In other words, the system automatically decides whether to use translation or compression mode, depending on whether the content can be scrolled.

3. Listen for soft keyboard display hiding

Sometimes the mechanism of the system itself is not what we want to achieve, we may want to manually change the layout while the soft keyboard is hidden, so that the soft keyboard pops up more aesthetically. This is where you need to listen for the display hiding of the soft keyboard.

I did not find the method to hide listening directly on the display of the soft keyboard. If someone finds the method, please be sure to tell me 1 tone. There is also this method for compression mode, translation mode is not a valid.

We can listen to the main window by rearranging it with the soft keyboard when it is displayed and hidden. If we set the mode to compression, then we can track the layout's onSizeChanged function, which might not be called if it is in translation mode.

We can rewrite the root layout because the height of the root layout does not change normally.

Assuming that the layout is linear and the mode is compression mode, let's write an example to hide some view when input method pops up, and show some view when input method hides.


public class ResizeLayout extends LinearLayout{ 
  private OnResizeListener mListener; 
  public interface OnResizeListener { 
   void OnResize(int w, int h, int oldw, int oldh); 
  } 
  public void setOnResizeListener(OnResizeListener l) { 
   mListener = l; 
  } 
  public ResizeLayout(Context context, AttributeSet attrs) { 
   super(context, attrs); 
  } 
  @Override 
  protected void onSizeChanged(int w, int h, int oldw, int oldh) {  
   super.onSizeChanged(w, h, oldw, oldh); 
   if (mListener != null) { 
    mListener.OnResize(w, h, oldw, oldh); 
   } 
  } 
}

In our Activity, we make the following method call:


public class InputMethodTestActivity extends Activity { 
  private static final int BIGGER = 1; 
  private static final int SMALLER = 2; 
  private static final int MSG_RESIZE = 1; 
  private static final int HEIGHT_THREADHOLD = 30; 
  class InputHandler extends Handler { 
   @Override 
   public void handleMessage(Message msg) { 
    switch (msg.what) { 
    case MSG_RESIZE: { 
     if (msg.arg1 == BIGGER) { 
      findViewById(R.id.bottom_layout).setVisibility(View.VISIBLE); 
     } else { 
      findViewById(R.id.bottom_layout).setVisibility(View.GONE); 
     } 
    } 
     break; 
    default: 
     break; 
    } 
    super.handleMessage(msg); 
   } 
  } 
  private InputHandler mHandler = new InputHandler(); 
  /** Called when the activity is first created. */ 
  @Override 
  public void onCreate(Bundle savedInstanceState) { 
   super.onCreate(savedInstanceState); 
   setContentView(R.layout.main); 
   ResizeLayout layout = (ResizeLayout) findViewById(R.id.root_layout); 
   layout.setOnResizeListener(new ResizeLayout.OnResizeListener() { 
    public void OnResize(int w, int h, int oldw, int oldh) { 
     int change = BIGGER; 
     if (h < oldh) { 
      change = SMALLER; 
     } 
     Message msg = new Message(); 
     msg.what = 1; 
     msg.arg1 = change; 
     mHandler.sendMessage(msg); 
    } 
   }); 
  } 
}

In particular, you cannot make changes to View directly in OnResizeListener, because the OnSizeChanged function is actually running in View's layout method. If you change the display property of view directly in onSizeChange, you will probably need to call the layout method again to display correctly. However, our method is called in layout, so an error occurs. Therefore, we adopt the method of Handler in the example.

I hope this article has been helpful for Android programming.


Related articles: