Android Tutorial Handle the soft keyboard with the IME library

Status
Not open for further replies.
Android has very good support for custom input method editors (IMEs).
The downside for this powerful feature is that interacting with the soft keyboard can be sometimes quite complicated.

This library includes several utilities that will help you better handle the soft keyboard.

The attached example demonstrates the available methods.

1724752241705.png


Note that the IME object should be initialized before it can be used.

Handling the screen size changed event
When the keyboard opens the available screen size becomes much shorter. By default if the EditText is located near the bottom of the screen, Android will "push" the whole activity and make the EditText visible. This mode is named "adjustPan" mode.

By calling IME.AddHeightChangedEvent you are changing the activity to "adjustSize" mode. In this mode the activity will not be pushed automatically. Instead the HeightChanged event will be raised when the keyboard is shown or hidden.

Update: You should explicitly set the adjustSize mode with the manifest editor. This is done by adding the following manifest editor code (for each activity):
B4X:
SetActivityAttribute(main, android:windowSoftInputMode, adjustResize|stateHidden)

For example the following code makes sure that the button at the bottom is always visible and sets the large EditText height to match the available height:
B4X:
Sub IME_HeightChanged(NewHeight As Int, OldHeight As Int)
   btnHideKeyboard.Top = NewHeight - btnHideKeyboard.Height
   EditText1.Height = btnHideKeyboard.Top - EditText1.Top
End Sub

The result is:

1724752272411.png


Note that this method will not work if the activity is in full screen mode (Issue 5497 - android - adjustResize windowSoftInputMode breaks when activity is fullscreen - Android).

Showing and hiding the keyboard
IME.ShowKeyboard - Sets the focus to the given view and opens the soft keyboard.
IME.HideKeyboard - Hides the keyboard (this method is the same as Phone.HideKeyboard).

Handle the action button
By calling IME.AddHandleActionEvent you can override the default behavior of the action button (the button that shows Next or Done).
This event is similar to EditText_EnterPressed event. However it is more powerful. It also allows you to handle the Next button and also to consume the message (and keep the keyboard open and the focus on the current EditText).

This can be useful in several cases.
For example in a chat application you can send the message when the user presses on the done button and keep the keyboard open by consuming the message.

You can also use it to validate the input before jumping to the next view by pressing on the Next button (note that the user will still be able to manually move to the next field).

You can use the Sender keyword to get the EditText that raised the event.
For example:
B4X:
Sub IME_HandleAction As Boolean
   Dim e As EditText
   e = Sender
   If e.Text.StartsWith("a") = False Then
      ToastMessageShow("Text must start with 'a'.", True)
      'Consume the event.
      'The keyboard will not be closed
      Return True
   Else
      Return False 'will close the keyboard
   End If
End Sub

Custom filters
EditText.InputType allows you to set the keyboard mode and the allowed input.
However there are situations where you need to use a custom filter. For example if you want to accept IP addresses (ex: 192.168.0.1). In this case none of the built-in types will work. Setting the input type to INPUT_TYPE_DECIMAL_NUMBERS will get you close but it will not allow the user to write more than a single dot.
IME.SetCustomFilter allows you to both set the keyboard mode and also to set the accepted characters.
In this case we will need a code such as:
B4X:
IME.SetCustomFilter(EditText3, EditText3.INPUT_TYPE_NUMBERS, "0123456789.")
Note that this is only a simple filter. It will accept the following input (which is not a valid IP address):
....9999.

Updates:

The example was updated and is now based on B4XPages. Note that additional code in the Main module (https://www.b4x.com/android/forum/t...or-managing-multiple-pages.118901/post-745090) and don't miss the manifest editor code.
 

Attachments

  • IME_Example.zip
    14.8 KB · Views: 223
Last edited:

dlfallen

Active Member
Licensed User
Longtime User
OK, so I have:

B4X:
Sub Query1_Click
QueryPnl.Visible = True
QueryTxt.RequestFocus
CallSubDelayed(Me, "ShowKB")
End Sub

Sub ShowKB
Dim IME As IME
IME.ShowKeyboard(QueryTxt)
End Sub

No errors on compiling, but no keyboard either.
 

dlfallen

Active Member
Licensed User
Longtime User
No it does not help. In fact I started with all of the statement in ShowKB and then moved them out when that did not woek.
 

dlfallen

Active Member
Licensed User
Longtime User
After much trial and error, I found a solution by using DoEvents.
B4X:
Sub ShowKB
DoEvents
Dim IME As IME
DoEvents
IME.ShowKeyboard(QueryTxt)
End Sub

Both DoEvents are needed to make this work. The placement of the DoEvents seems odd. I have tried various placement of the two Doevents within the code and only this one seems to work. A single DoEvents does not work regardless of where it is placed.

Whatever works, I guess, but this is not the kind of insight I can build on in the future.
 

Rusty

Well-Known Member
Licensed User
Longtime User
Is there a way to force the keyboard microphone to appear (and be enabled)? my keyboards do not show this.
Thanks,
Rusty
 

derez

Expert
Licensed User
Longtime User
Am I right that the only way to input a negative decimal number is by a full text keyboard ?
Even if the minus symbol is visible in some devices, it is not active in number or decimal kbd.
The IME filters the keys action but they are still there.
 

mrazamerchant

Member
Licensed User
Longtime User
HI, does ime.showkeyboard works on activity create event? What I am looking for is on click of a button I am loading a new activity which has a edittext, I need to load the keyboard so user can start typing. Right now the focus is on edittext but keyboard doesn't show up, user has to click on edittext to bring the keyboard.

Sub Activity_Create(FirstTime AsBoolean)
Activity.LoadLayout("drglist")
IME.Initialize("IME")
IME.AddHandleActionEvent(txtSearchBrand)
Activity.SetBackgroundImage(LoadBitmap(File.DirAssets, "grey.jpg"))
IME.ShowKeyboard(txtSearchBrand)
End Sub
 
Last edited:

johnaaronrose

Active Member
Licensed User
Longtime User
When an activity in my app runs in portrait mode (with its own variant), there is sufficient room for the keyboard to display without any of the views being 'hidden'. However in landscape mode (with its own variant), the keyboard appears and all the views are 'hidden' (due to the box for entering an EditText value being much higher than its box on the screen). The layout in this case consists of a 'line' with one Label & a button, followed by a line with 3 Labels, followed by a line with 3 EditTexts. A screen shot is attached from the Abstract Designer & a screenshot showing the situation at runtime.
PS I'm not currently using the IME.AddHeightChangedEvent but would happy to use it in order to solve this problem if knew how to do it.
 

Attachments

  • AbstractDesignerScreenshot.png
    AbstractDesignerScreenshot.png
    24.4 KB · Views: 585
  • TooHighAnEditTextEntryBoxScreenshot.jpg
    TooHighAnEditTextEntryBoxScreenshot.jpg
    50.2 KB · Views: 564

johnaaronrose

Active Member
Licensed User
Longtime User
By default the keyboard appears this way in landscape orientation.

You can disable this behavior with this code:
B4X:
Dim jo As JavaObject = EditText1.Text
jo.RunMethod("setImeOptions", Array As Object(268435456)) 'IME_FLAG_NO_EXTRACT_UI
When I used the code below, I got "java.lang.RuntimeException: Method: setIMEOptions not found in: java.lang.string:
B4X:
Dim JO As JavaObject
JO = edtMap.Text
JO.RunMethod("setImeOptions", Array As Object(268435456)) 'IME_FLAG_NO_EXTRACT_UI

I have the Java Object library included so no compilation errors. Could the exception be due to running the app on a Gingerbread phone?

Webpage for URL https://developer.android.com/reference/android/view/inputmethod/EditorInfo.html
states for IME_FLAG_NO_EXTRACT_UI that "The part of the UI visible to the user may not be responsive to touch because the IME will receive touch events, which may confuse the user; use IME_FLAG_NO_FULLSCREEN instead for a better experience. Using this flag is discouraged and it may become deprecated in the future. Its meaning is unclear in some situations and it may not work appropriately on older versions of the platform.". So would it be better to use IME_FLAG_NO_FULLSCREEN instead?

Also, which flag should I use to 'reset' the behaviour due to the above flag? The reason I ask this is that I have a sub named ResizeViews (called in Activity_Create & Activity_Pause) which does as its name suggests using SetLayout commands with different ones depending on which 'orientation' (i.e. portrait or landscape) is current. That is where I put the above 'JavaObject' code.
 

johnaaronrose

Active Member
Licensed User
Longtime User
My mistake. It should be Dim jo As JavaObject = EditText1 (not .Text).
OK now for landscape input except that keyboard now shows Done rather than Next. Also, after clicking Done, keyboard is hidden (as executed by code) but there is no automatic progression (as requested by code shown below in IME_HandleAction event's code for the edtMap EditText):
B4X:
Dim R As Reflector
    R.Target = edtMap
  R.RunMethod2("setFocusable", TrueFalse, "java.lang.boolean")
  R.RunMethod2("setFocusableInTouchMode", TrueFalse, "java.lang.boolean")

So should I use IME_FLAG_NO_FULLSCREEN rather than IME_FLAG_NO_EXTRACT_UI due to the following:
Webpage for URL https://developer.android.com/reference/android/view/inputmethod/EditorInfo.html
states for IME_FLAG_NO_EXTRACT_UI that "The part of the UI visible to the user may not be responsive to touch because the IME will receive touch events, which may confuse the user; use IME_FLAG_NO_FULLSCREEN instead for a better experience. Using this flag is discouraged and it may become deprecated in the future. Its meaning is unclear in some situations and it may not work appropriately on older versions of the platform."

Also, which flag should I use to 'reset' the behaviour due to the above flag? The reason I ask this is that I have a sub named ResizeViews (called in Activity_Create & Activity_Pause) which does as its name suggests using SetLayout commands with different ones depending on which 'orientation' (i.e. portrait or landscape) is current. That is where I put the above 'JavaObject' code.
 
Status
Not open for further replies.
Top