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: 161
Last edited:

Dirk A

Member
Licensed User
Longtime User
It seems that the problem does not occur when the IME stuff is initialised before the layout is created. It doesn't make sense to me , but it works so it's ok :)
 

Roger Garstang

Well-Known Member
Licensed User
Longtime User
I'm having some weird results with this. I have a screen layout containing a logo at the top, a username and password label/edit text, and a next button in the bottom right corner. All built in code/no designer. In Landscape the username/password labels and edit texts are all one line across the screen. In Portrait I stack them up all on their own line (4 lines). Next Button is always in right bottom corner.

B4X:
Sub ime1_HandleAction As Boolean
   Dim edtTxt As EditText
   
   edtTxt = Sender
   
   If edtTxt = usernameTxt Then
      passwordTxt.RequestFocus
      Return True
   Else
      nextBtn_Click
   End If
End Sub

Works fine and navigates between the controls as well as clicking the bottom right Next button. My device does the full screen keyboard in landscape mode though which for some reason always shows the Done button. In Portrait shows Next then Done on the Last Edit Text's keyboard as it should. Your example code shows Next button in the Full Screen keyboard properly, so I'm not sure if it is related to the number of Edit Texts on screen or being built in designer. I don't set ForceDone on any Edit Texts.

B4X:
Sub ime1_HeightChanged (NewHeight As Int, OldHeight As Int)
   If NewHeight < OldHeight Then ' Keyboard Open
      Logo.Visible = False
      If Activity.Width > Activity.Height Then ' Landscape
         userLbl.Top = 5dip
         username.Top = 5dip
         passLbl.Top = 5dip
         password.Top = 5dip
      Else
         userLbl.Top = 5dip
         username.Top = userLbl.Top + userLbl.Height + 2dip
         passLbl.Top = username.Top + username.Height + 5dip
         password.Top = passLbl.Top + passLbl.Height + 2dip
      End If
      nextBtn.Top = NewHeight - nextBtn.Height - 5dip
   Else ' Keyboard Closed
      Logo.Visible = True
      userLbl.Top = userLbl.Tag
      username.Top = username.Tag
      passLbl.Top = passLbl.Tag
      password.Top = password.Tag
      nextBtn.Top = nextBtn.Tag
   End If
End Sub

Doesn't work though (views and logo never move or hide). If I put some Toast Messages in there I sometimes see them, but it is delayed like the code doesn't run until after the keyboard closes. If I reverse my logic for NewHeight < OldHeight and the keyboard closes it runs and draws how I expect the views when keyboard is open. The Tag values are where I store Top after adding the controls to the view so I can restore them when the keyboard closes. Is there something I'm not doing right here? Your example works fine, but it only moves one button that is always at the bottom.
 
Last edited:

Roger Garstang

Well-Known Member
Licensed User
Longtime User
Ok...this gets weirder. After some debugging it appears Android/The Keyboard call this method twice in Portrait mode. Doesn't call it at all in Landscape (Expected with Full Screen Keyboard). It first calls it correct with numbers like New=548 Old=948 then again with New=948 Old=548, so something is overriding it. I loaded it on a Galaxy Nexus and could actually see it happening- It draws the views correct for about half a second then redraws them and bumps the screen up where the focused Edit Text is just above the keyboard.

Just for giggles I commented out the code changing the location of Username Edit Text. On the Motorola ET1 it made no difference, but on the Galaxy Nexus it positioned as expected when that view got focus, but since the code didn't move it the keyboard covered it.

It only seems to call this function in the initial keyboard slide too. After whatever happens to override it the function never gets called again like it took away the call and reverted to standard. If I rotate then rotate back it will call again. On the Galaxy Nexus, even when not moving the Username Edit Box where it draws without moving back to standard, it only calls it that first time until rotating.

Also, if I'm in Portrait mode with keyboard showing and rotate, it will call the function twice too even though no keyboard is shown in Landscape. Weird numbers too, something like- New=60 Old=548 then New=548 Old=60.
 
Last edited:

salmander

Active Member
Licensed User
Longtime User
Is it not possible to show the keyboard on "Activity_Resume" event? What actually happens is the editText view does gets focus but the keyboard never opens. No matter what editText view i set the focus to.
However, the keyboard does opens, when I put the same code on Button onClick event.

Anyone noticed this behaviour?
B4X:
IME.ShowKeyboard(EdtText1)
 

salmander

Active Member
Licensed User
Longtime User
The state of the keyboard when the activity appears is set in the manifest file.
You should use this code (manifest editor):
B4X:
SetActivityAttribute(main, android:windowSoftInputMode, stateAlwaysVisible)
Thanks Erel, it did work.

Cheers for that.
 

Roger Garstang

Well-Known Member
Licensed User
Longtime User
Thanks from me too, I decided to dive into this manifest stuff and added:

SetActivityAttribute(main, android:windowSoftInputMode, adjustResize)

To my Manifest in the file above giving me issues and now everything works!

So, is there a bug in the IME library where it isn't adding this like it states above due to me not using layouts and coding the views by hand?

Now, some questions. It looks like "main" is the activity name and the Manifest is Project wide, so am I going to need to add this line for each of my Activities I want the IME to function on? And the actual name is "Main", so does this file ignore case or force lowercase?
 

Roger Garstang

Well-Known Member
Licensed User
Longtime User
Had another road block after adding the line above where now if the screen is rotated while the keyboard is out it was like it was calling Create with an activity sized to the leftover keyboard area and the keyboard area was then left totally black and non-functional.

I added some calls to force the screen orientation so when the keyboard is out it can't rotate. Works fine in Portrait...works in Landscape's full screen keyboard too although it seems to just delay the ability to rotate just long enough for whatever happens to stop and actually allows the rotate in the end but without the screen corruption.

Looks like I'm good, but IME library may need some tweaking. Seems like some type of activity flag issues with coded layouts. I tried various combinations of the windowSoftInputMode flags or'd in with | but they didn't stop the screen corruption, so something else must be needed to allow rotating properly.
 

Theera

Well-Known Member
Licensed User
Longtime User
It will be better,if you can select language softkeyboard. I'm Thai people,my users can input English or Thai Language. If I need show softKeyboard Thai before,How can I do?
Best Regards
Theera
 

PeterPetSil

Member
Licensed User
Longtime User
I'm trying to show the keyboard right after I display the Input Dialog, but the ShowKeyboard function requires a View object.
You have to pas the activity object to this function?

How can I do this?

Thanks!
 

Roger Garstang

Well-Known Member
Licensed User
Longtime User
Some devices let you hold/longpress the menu key to popup the keyboard. I happen to have one that does. For most dialogs like input lists and such it pops up behind the dialog (Keyboard isn't useful for them anyway since no Edit Box), but for the Input Dialog it actually pops up in front and if the Edit Box has focus it will type in it. You may be able to ask the Dev of the library if they would be able to add a parameter that returns the reference to the Edit Box sort of how Listviews expose their labels, but to the actual view. Sounds like a pretty good addition for all the Edit Boxes if possible in what dialogs have them. I don't know if the Dev built them or if they are internal and if Android exposes them though.
 

Roger Garstang

Well-Known Member
Licensed User
Longtime User
Playing with the Log it appears that dialog is called com.android.internal.view.IInputMethodClient (First time actually needing to use the log too, and there doesn't appear to be an off switch once it is on???). This appears to indicate that it is internal. Might be possible with some kind of Manifest hack to force it visible. This doesn't work, but something like:

B4X:
AddApplicationText(<activity
   android:windowSoftInputMode="stateAlwaysVisible"
   android:name="com.android.internal.view.IInputMethodClient">
</activity>)

Maybe someone with more knowledge than I would know of a way to force the keyboard for it in the Manifest. There is still the option of the Dev too since they have access to InputType and such for the Edit Box there may be a way to do more with it. I even tried a few other flags there I use in other apps hoping one would make the keyboard show but no luck. Could be a Reflection option too...searching right now for something to show it without needing a view. (So Far I found toggleSoftInput...seeing how it works now)
 

Roger Garstang

Well-Known Member
Licensed User
Longtime User

Penko

Active Member
Licensed User
Longtime User
What is the correct way to bring the following IME keyboard? I've tried multiple alternatives but can't seem to make it work. In contrary, I see this numeric keyboard is widely used so my mistake should be pretty straightforward.

I've tried assigning "NUMBER" and "NUMBER_DECIMAL" in the view properties but the best I get is shown on the second attached picture.
 

Attachments

  • IME.png
    IME.png
    71.1 KB · Views: 845
  • ime2.png
    ime2.png
    33.7 KB · Views: 1,101
Status
Not open for further replies.
Top