I have a EditText
component, and, of course, if you click on it, the Android keypad is shown, allowing the user to input text. As far as I know, all Android software keyboards have (at least) a letter mode (ABC
) and a symbols mode (?123
). Their default view is the letter mode.
Now when the keypad is shown when the EditText
component is clicked, I want the symbols mode to be shown by default. The user will still be able to switch to the letter mode.
Is there a way to achieve that? If yes, how?
I'm posting this because I don't think any of the answers actually address the question. The screenshot in the question does not correspond to a particular InputType's default state. So, switching InputTypes will not give you the layout from the screenshot.
(based on my research...)
Support for symbol input is not governed by any contract. One can very well leave symbols out when creating their own InputMethod
. OR, they can add pagination support to provide access to 100s of symbols. Can this be bound by a contract? May be. But, it isn't at present.
Input method framework does not allow direct communication between the client and the IME. All communication happens either through the InputMethodManager
or through InputConnection
— a one-way channel. Switching to symbols using ?123
is, however, an internal event — not a defined state/action. Client applications cannot switch to it. There's no public (or hidden) API to make this happen.
InputType
indicates something entirely different to an IME. Not sure why everyone is recommending its use. You may of course find that a particular InputType
provides most of the required keys. But that isn't the same as show[ing] Android keyboard with symbols mode by default.
Possible workaround:
We'll create a custom EditText
. We don't have to. It'll just keep everything in one place, and save us from copy-paste nightmare.
public class CusEditText extends EditText {
private final int mDefinedActionId;
public CusEditText(Context context, AttributeSet attrs) {
super(context, attrs);
// Corresponds to 'android:imeActionId' value
mDefinedActionId = getResources().getInteger(R.integer.definedActionId);
setOnEditorActionListener(new OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
Log.i("CusEditText", "onEditorAction, actionId = " + actionId);
// Only bother if (...)
if (actionId == mDefinedActionId) {
// Check if current InputType is NUMBER
if ((getInputType() & InputType.TYPE_CLASS_NUMBER) != 0) {
// Toggle
setImeActionLabel("NUM", mDefinedActionId);
setInputType(InputType.TYPE_CLASS_TEXT);
} else {
// Current InputType is TEXT // Toggle
setImeActionLabel("ABC", mDefinedActionId);
setInputType(InputType.TYPE_CLASS_NUMBER);
}
// We've handled this
return true;
}
// Let someone else worry about this
return false;
}
});
}
}
Next, we need to define definedActionId
. Open or create res/values/integers.xml
and add:
<integer name="definedActionId">-100</integer>
-100
is an arbitrary value. I checked EditorInfo
and the actionIds (IME_ACTION_XXXX
) were >= 0. -100
seems like a good candidate.
In xml, your layout will look like:
<com.your.packagename.CusEditText
android:layout_width="blah"
android:layout_height="blah"
android:inputType="number"
android:imeActionId="@integer/definedActionId"
android:imeActionLabel="ABC"/>
<!-- Probably use @string resource in place of ABC -->
There's not much to explain. IME will launch in NUMBER mode. Instead of a checkmark icon, it'll display ABC
. On click, we intercept the actionId and toggle between NUMBER and TEXT input. We're using setInputType(...)
because it not only updates the InputType
, it also restarts the IME with changes. setRawInputType(...)
only updates the InputType
.
Issues:
As you can tell, this isn't really a solution. If the user closes the keyboard(using the back
button) in TEXT mode, the keyboard will remain in the TEXT mode when they open it again. To go to the NUMBER mode, user will have to click NUM
. Also, in TEXT mode, user will see NUM
as the action, along with ?123
option. This doesn't break anything, but does take away from the UX.
We can't do anything about ?123
showing in TEXT mode for reasons listed above. But, we can try to make sure that the keyboard always opens in the NUMBER mode. I'll provide a rough sketch of how we'll do that. Its not straight-forward since we (developers) are not privy to events such as keyboard closing or opening. Updated CusEditText
:
public class CusEditText extends EditText {
private final int mDefinedActionId;
private long mLastEditorActionTime = 0L;
public CusEditText(Context context, AttributeSet attrs) {
super(context, attrs);
// Corresponds to 'android:imeActionId' value
mDefinedActionId = getResources().getInteger(R.integer.definedActionId);
setOnEditorActionListener(new OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
Log.i("CusEditText", "onEditorAction, actionId = " + actionId);
// Only bother if (...)
if (actionId == mDefinedActionId) {
// setInputType(...) will restart the IME
// and call finishComposingText()
// see below
mLastEditorActionTime = SystemClock.elapsedRealtime();
// Check if current InputType is NUMBER
if ((getInputType() & InputType.TYPE_CLASS_NUMBER) != 0) {
// Toggle
setImeActionLabel("NUM", mDefinedActionId);
setInputType(InputType.TYPE_CLASS_TEXT);
} else {
// Current InputType is TEXT // Toggle
setImeActionLabel("ABC", mDefinedActionId);
setInputType(InputType.TYPE_CLASS_NUMBER);
}
// We've handled this
return true;
}
// Let someone else worry about this
return false;
}
});
}
@Override
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
InputConnection inputConnection = super.onCreateInputConnection(outAttrs);
return new CusInputConnectionWrapper(inputConnection, false);
}
private class CusInputConnectionWrapper extends InputConnectionWrapper {
private CusInputConnectionWrapper(InputConnection target, boolean mutable) {
super(target, mutable);
}
@Override
public boolean finishComposingText() {
Log.i("CICW", "finishComposingText");
// Ignore finishComposingText for 1 second (1000L)
if (SystemClock.elapsedRealtime() - mLastEditorActionTime > 1000L) {
if ((getInputType() & InputType.TYPE_CLASS_NUMBER) == 0) {
// InputConnection is no longer valid.
// Switch back to NUMBER iff required
setImeActionLabel("ABC", mDefinedActionId);
setInputType(InputType.TYPE_CLASS_NUMBER);
}
}
return super.finishComposingText();
}
}
}
Again, code is self-explanatory. We create a InputConnectionWrapper
and listen for the finishComposingText()
callback. If we're manually switching between TEXT
and NUMBER
, we use a flag since finishComposingText()
will automatically be called. Else, we check if input type is set to TEXT
and change it to NUMBER
. I am not sure if finishComposingText()
is the right method for interpreting keyboard closing/opening. Testing on API 21, vanilla android, this seems to work. More tests will be required.
I really hope someone can come up with a better, more robust solution than this - or modify my workaround so that it doesn't look like one.
Summary
Task at hand is to provide functionality of switching between NUMBER & TEXT input modes around existing Input Method Engines (IMEs). The first approach was to use imeActionLabel & imeActionId
in the switching mechanism. This approach worked well with Google's keyboard (this is the imeActionLabel), but failed with Samsung's - imeActionLabel
failed to show up in portrait (without extract). Possible workaround is to include the toggle button in the app's own UI.
Even with Google's keyboard, the letters (text) fail to show up when the mode switches back to NUMBER after inputting letters. This problem was fixed (at least on tested devices) by using flag flagNoExtractUi
which prevents the IME from entering fullscreen mode in landscape orientation.
Final solution (pending implementation & testing)
- The IME starts in the NUMBER input mode (95% use-cases involve number input)
- A button is added to app's UI (next to the
EditText
) for switching between NUMBER & TEXT mode
- User can switch from NUMBER to TEXT without any restrictions. Switching back from TEXT to NUMBER requires that no alphabets have been added.
- InputType is preserved between keyboard closing & reopening. Example: If the user switches to TEXT mode and closes the keyboard, it will open in the TEXT mode. The InputType is not reset.
For more information about the approaches tried, refer to this discussion thread.
Screenshots
Default (NUMBER):
Switched to TEXT:
Recorded video link
I agree it is an InputType. If you want to show only numbers to your user then you would add the following to you xml document for your edit text:
android:inputType="number"
However if you set it as number then the user has to enter a number. But you can add additional types as well like numbers and email addresses such as:
android:inputType="number|textEmailAddress"
Check out http://developer.android.com/reference/android/text/InputType.html for more options. You can also check out what eclipse or android studio shows you under "inputType"
I believe you are looking to set the InputType of your edit text.
http://developer.android.com/reference/android/text/InputType.html
I'm not sure which you would use though you may have to play around a bit.
The only way to do this is by setting the inputType of your EditText
.
If you want to set this property in the onCreate()
(or inside a custom View
's constructor) you can use the method setRawInputType():
mEditText.setRawInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL);
Otherwise, if you need to set this property after the onCreate()
(or after a custom View
's constructor), you can use the method setInputType():
mEditText.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL);
Obviously you can also specify the property at XML level:
android:inputType="number|numberDecimal"
You can play around with different flags to find the best composed filter.
Programmatically it is possible with little bit of tweak to the usual flow. First you have to set editText as:
editText.setInputType(InputType.TYPE_CLASS_NUMBER);
Then you have to listen for keyevent. On pressing of pound set the InputType again to InputType.TYPE_CLASS_TEXT. This should work as it works for me.
editText.setOnKeyListener(new View.OnKeyListener()
{
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
// TODO Auto-generated method stub
Log.d("KeyBoard", "Keyboard Test Key Hit");
switch (keyCode) {
KeyEvent.KEYCODE_POUND:
if(editText.setInputType(InputType.TYPE_CLASS_TEXT);
{
editText.setInputType(InputType.TYPE_CLASS_TEXT);
return true;
}
Same thing I've answered i: EditText with number keypad by default, but allowing alphabetic characters