I am wondering if there is a way to handle the user pressing Enter while typing in an EditText, something like the onSubmit HTML event.
Also wondering if there is a way to manipulate the virtual keyboard in such a way that the "Done" button is labeled something else (for example "Go") and performs a certain action when clicked (again, like onSubmit).
I am wondering if there is a way to
handle the user pressing Enter while
typing in an EditText, something like
the onSubmit HTML event.
Yes.
Also wondering if there is a way to
manipulate the virtual keyboard in
such a way that the "Done" button is
labeled something else (for example
"Go") and performs a certain action
when clicked (again, like onSubmit).
Also yes.
You will want to look at the android:imeActionId and android:imeOptions attributes, plus the setOnEditorActionListener() method, all on TextView.
For changing the text of the "Done" button to a custom string, use:
mEditText.setImeActionLabel("Custom text", KeyEvent.KEYCODE_ENTER);
final EditText edittext = (EditText) findViewById(R.id.edittext);
edittext.setOnKeyListener(new OnKeyListener() {
public boolean onKey(View v, int keyCode, KeyEvent event) {
// If the event is a key-down event on the "enter" button
if ((event.getAction() == KeyEvent.ACTION_DOWN) &&
(keyCode == KeyEvent.KEYCODE_ENTER)) {
// Perform action on key press
Toast.makeText(HelloFormStuff.this, edittext.getText(), Toast.LENGTH_SHORT).show();
return true;
}
return false;
}
});
Here's what you do. It's also hidden in the Android Developer's sample code 'Bluetooth Chat'. Replace the bold parts that say "example" with your own variables and methods.
First, import what you need into the main Activity where you want the return button to do something special:
import android.view.inputmethod.EditorInfo;
import android.widget.TextView;
import android.view.KeyEvent;
Now, make a variable of type TextView.OnEditorActionListener for your return key (here I use exampleListener);
TextView.OnEditorActionListener exampleListener = new TextView.OnEditorActionListener(){
Then you need to tell the listener two things about what to do when the return button is pressed. It needs to know what EditText we're talking about (here I use exampleView), and then it needs to know what to do when the Enter key is pressed (here, example_confirm()). If this is the last or only EditText in your Activity, it should do the same thing as the onClick method for your Submit (or OK, Confirm, Send, Save, etc) button.
public boolean onEditorAction(TextView exampleView, int actionId, KeyEvent event) {
if (actionId == EditorInfo.IME_NULL
&& event.getAction() == KeyEvent.ACTION_DOWN) {
example_confirm();//match this behavior to your 'Send' (or Confirm) button
}
return true;
}
Finally, set the listener (most likely in your onCreate method);
exampleView.setOnEditorActionListener(exampleListener);
This page describes exactly how to do this.
https://developer.android.com/training/keyboard-input/style.html
Set the android:imeOptions then you just check the actionId in onEditorAction. So if you set imeOptions to 'actionDone' then you would check for 'actionId == EditorInfo.IME_ACTION_DONE' in onEditorAction. Also, make sure to set the android:inputType.
If using Material Design put code in TextInputEditText.
Here's the EditText from the example linked above:
<EditText
android:id="#+id/search"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:hint="#string/search_hint"
android:inputType="text"
android:imeOptions="actionSend" />
You can also set this programmatically using the setImeOptions(int) function. Here's the OnEditorActionListener from the example linked above:
EditText editText = (EditText) findViewById(R.id.search);
editText.setOnEditorActionListener(new OnEditorActionListener() {
#Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
boolean handled = false;
if (actionId == EditorInfo.IME_ACTION_SEND) {
sendMessage();
handled = true;
}
return handled;
}
});
Hardware keyboards always yield enter events, but software keyboards return different actionIDs and nulls in singleLine EditTexts. This code responds every time the user presses enter in an EditText that this listener has been set to, regardless of EditText or keyboard type.
import android.view.inputmethod.EditorInfo;
import android.view.KeyEvent;
import android.widget.TextView.OnEditorActionListener;
listener=new TextView.OnEditorActionListener() {
#Override
public boolean onEditorAction(TextView view, int actionId, KeyEvent event) {
if (event==null) {
if (actionId==EditorInfo.IME_ACTION_DONE);
// Capture soft enters in a singleLine EditText that is the last EditText.
else if (actionId==EditorInfo.IME_ACTION_NEXT);
// Capture soft enters in other singleLine EditTexts
else return false; // Let system handle all other null KeyEvents
}
else if (actionId==EditorInfo.IME_NULL) {
// Capture most soft enters in multi-line EditTexts and all hard enters.
// They supply a zero actionId and a valid KeyEvent rather than
// a non-zero actionId and a null event like the previous cases.
if (event.getAction()==KeyEvent.ACTION_DOWN);
// We capture the event when key is first pressed.
else return true; // We consume the event when the key is released.
}
else return false;
// We let the system handle it when the listener
// is triggered by something that wasn't an enter.
// Code from this point on will execute whenever the user
// presses enter in an attached view, regardless of position,
// keyboard, or singleLine status.
if (view==multiLineEditText) multiLineEditText.setText("You pressed enter");
if (view==singleLineEditText) singleLineEditText.setText("You pressed next");
if (view==lastSingleLineEditText) lastSingleLineEditText.setText("You pressed done");
return true; // Consume the event
}
};
The default appearance of the enter key in singleLine=false gives a bent arrow enter keypad. When singleLine=true in the last EditText the key says DONE, and on the EditTexts before it it says NEXT. By default, this behavior is consistent across all vanilla, android, and google emulators. The scrollHorizontal attribute doesn't make any difference. The null test is important because the response of phones to soft enters is left to the manufacturer and even in the emulators, the vanilla Level 16 emulators respond to long soft enters in multi-line and scrollHorizontal EditTexts with an actionId of NEXT and a null for the event.
I know this is a year old, but I just discovered this works perfectly for an EditText.
EditText textin = (EditText) findViewById(R.id.editText1);
textin.setInputType(InputType.TYPE_CLASS_TEXT);
It prevents anything but text and space. I could not tab, "return" ("\n"), or anything.
In your xml, add the imeOptions attribute to the editText
<EditText
android:id="#+id/edittext_additem"
...
android:imeOptions="actionDone"
/>
Then, in your Java code, add the OnEditorActionListener to the same EditText
mAddItemEditText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
#Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if(actionId == EditorInfo.IME_ACTION_DONE){
//do stuff
return true;
}
return false;
}
});
Here is the explanation-
The imeOptions=actionDone will assign "actionDone" to the EnterKey. The EnterKey in the keyboard will change from "Enter" to "Done". So when Enter Key is pressed, it will trigger this action and thus you will handle it.
I had a similar purpose. I wanted to resolve pressing the "Enter" key on the keyboard (which I wanted to customize) in an AutoCompleteTextView which extends TextView. I tried different solutions from above and they seemed to work. BUT I experienced some problems when I switched the input type on my device (Nexus 4 with AOKP ROM) from SwiftKey 3 (where it worked perfectly) to the standard Android keyboard (where instead of handling my code from the listener, a new line was entered after pressing the "Enter" key. It took me a while to handle this problem, but I don't know if it will work under all circumstances no matter which input type you use.
So here's my solution:
Set the input type attribute of the TextView in the xml to "text":
android:inputType="text"
Customize the label of the "Enter" key on the keyboard:
myTextView.setImeActionLabel("Custom text", KeyEvent.KEYCODE_ENTER);
Set an OnEditorActionListener to the TextView:
myTextView.setOnEditorActionListener(new OnEditorActionListener()
{
#Override
public boolean onEditorAction(TextView v, int actionId,
KeyEvent event)
{
boolean handled = false;
if (event.getAction() == KeyEvent.KEYCODE_ENTER)
{
// Handle pressing "Enter" key here
handled = true;
}
return handled;
}
});
I hope this can help others to avoid the problems I had, because they almost drove me nuts.
Just as an addendum to Chad's response (which worked almost perfectly for me), I found that I needed to add a check on the KeyEvent action type to prevent my code executing twice (once on the key-up and once on the key-down event).
if (actionId == EditorInfo.IME_NULL && event.getAction() == KeyEvent.ACTION_DOWN)
{
// your code here
}
See http://developer.android.com/reference/android/view/KeyEvent.html for info about repeating action events (holding the enter key) etc.
You can also do it..
editText.setOnKeyListener(new OnKeyListener() {
#Override
public boolean onKey(View v, int keyCode, KeyEvent event)
{
if (event.getAction() == KeyEvent.ACTION_DOWN
&& event.getKeyCode() == KeyEvent.KEYCODE_ENTER)
{
Log.i("event", "captured");
return false;
}
return false;
}
});
If you use DataBinding, see https://stackoverflow.com/a/52902266/2914140 and https://stackoverflow.com/a/67933283/2914140.
Bindings.kt:
#BindingAdapter("onEditorEnterAction")
fun EditText.onEditorEnterAction(callback: OnActionListener?) {
if (callback == null) setOnEditorActionListener(null)
else setOnEditorActionListener { v, actionId, event ->
val imeAction = when (actionId) {
EditorInfo.IME_ACTION_DONE,
EditorInfo.IME_ACTION_SEND,
EditorInfo.IME_ACTION_GO -> true
else -> false
}
val keydownEvent = event?.keyCode == KeyEvent.KEYCODE_ENTER
&& event.action == KeyEvent.ACTION_DOWN
if (imeAction or keydownEvent) {
callback.enterPressed()
return#setOnEditorActionListener true
}
return#setOnEditorActionListener false
}
}
interface OnActionListener {
fun enterPressed()
}
layout.xml:
<data>
<variable
name="viewModel"
type="YourViewModel" />
</data>
<EditText
android:imeOptions="actionDone|actionSend|actionGo"
android:singleLine="true"
android:text="#={viewModel.message}"
app:onEditorEnterAction="#{() -> viewModel.send()}" />
First, you have to set EditText listen to key press
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Set the EditText listens to key press
EditText edittextproductnumber = (EditText) findViewById(R.id.editTextproductnumber);
edittextproductnumber.setOnKeyListener(this);
}
Second, define the event upon the key press, for example, event to set TextView's text:
#Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
// TODO Auto-generated method stub
// Listen to "Enter" key press
if ((event.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_ENTER))
{
TextView textviewmessage = (TextView) findViewById(R.id.textViewmessage);
textviewmessage.setText("You hit 'Enter' key");
return true;
}
return false;
}
And finally, do not forget to import EditText,TextView,OnKeyListener,KeyEvent at top:
import android.view.KeyEvent;
import android.view.View.OnKeyListener;
import android.widget.EditText;
import android.widget.TextView;
password.setOnEditorActionListener(new TextView.OnEditorActionListener() {
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if(event != null && event.getKeyCode() == KeyEvent.KEYCODE_ENTER && event.getAction() == KeyEvent.ACTION_DOWN) {
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(InputMethodManager.SHOW_IMPLICIT, 0);
submit.performClick();
return true;
}
return false;
}
});
Works very fine for me
In addition hide keyboard
working perfectly
public class MainActivity extends AppCompatActivity {
TextView t;
Button b;
EditText e;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
b = (Button) findViewById(R.id.b);
e = (EditText) findViewById(R.id.e);
e.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (before == 0 && count == 1 && s.charAt(start) == '\n') {
b.performClick();
e.getText().replace(start, start + 1, ""); //remove the <enter>
}
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
#Override
public void afterTextChanged(Editable s) {}
});
b.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
b.setText("ok");
}
});
}
}
working perfectly
editText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
#Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if (actionId != 0 || event.getAction() == KeyEvent.ACTION_DOWN) {
// Action
return true;
} else {
return false;
}
}
});
Xml
<EditText
android:id="#+id/editText2"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:hint="#string/password"
android:imeOptions="actionGo|flagNoFullscreen"
android:inputType="textPassword"
android:maxLines="1" />
This should work
input.addTextChangedListener(new TextWatcher() {
#Override
public void afterTextChanged(Editable s) {}
#Override
public void beforeTextChanged(CharSequence s, int start,
int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start,
int before, int count) {
if( -1 != input.getText().toString().indexOf( "\n" ) ){
input.setText("Enter was pressed!");
}
}
});
Type this code in your editor so that it can import necessary modules.
query.setOnEditorActionListener(new TextView.OnEditorActionListener() {
#Override
public boolean onEditorAction(TextView textView, int actionId, KeyEvent keyEvent) {
if(actionId == EditorInfo.IME_ACTION_DONE
|| keyEvent.getAction() == KeyEvent.ACTION_DOWN
|| keyEvent.getAction() == KeyEvent.KEYCODE_ENTER) {
// Put your function here ---!
return true;
}
return false;
}
});
you can use this way
editText.setOnEditorActionListener((v, actionId, event) -> {
if (actionId == EditorInfo.IME_ACTION_DONE) {
// Do some things
return true;
}
return false;
});
you can see list of action there.
For example:
IME_ACTION_GO
IME_ACTION_SEARCH
IME_ACTION_SEND
This works fine on LG Android phones. It prevents ENTER and other special characters to be interpreted as normal character. Next or Done button appears automatically and ENTER works as expected.
edit.setInputType(InputType.TYPE_CLASS_TEXT);
Here's a simple static function that you can throw into your Utils or Keyboards class that will execute code when the user hits the return key on a hardware or software keyboard. It's a modified version of #earlcasper's excellent answer
/**
* Return a TextView.OnEditorActionListener that will execute code when an enter is pressed on
* the keyboard.<br>
* <code>
* myTextView.setOnEditorActionListener(Keyboards.onEnterEditorActionListener(new Runnable()->{
* Toast.makeText(context,"Enter Pressed",Toast.LENGTH_SHORT).show();
* }));
* </code>
* #param doOnEnter A Runnable for what to do when the user hits enter
* #return the TextView.OnEditorActionListener
*/
public static TextView.OnEditorActionListener onEnterEditorActionListener(final Runnable doOnEnter){
return (__, actionId, event) -> {
if (event==null) {
if (actionId == EditorInfo.IME_ACTION_DONE) {
// Capture soft enters in a singleLine EditText that is the last EditText.
doOnEnter.run();
return true;
} else if (actionId==EditorInfo.IME_ACTION_NEXT) {
// Capture soft enters in other singleLine EditTexts
doOnEnter.run();
return true;
} else {
return false; // Let system handle all other null KeyEvents
}
} else if (actionId==EditorInfo.IME_NULL) {
// Capture most soft enters in multi-line EditTexts and all hard enters.
// They supply a zero actionId and a valid KeyEvent rather than
// a non-zero actionId and a null event like the previous cases.
if (event.getAction()==KeyEvent.ACTION_DOWN) {
// We capture the event when key is first pressed.
return true;
} else {
doOnEnter.run();
return true; // We consume the event when the key is released.
}
} else {
// We let the system handle it when the listener
// is triggered by something that wasn't an enter.
return false;
}
};
}
InputType on the textfield must be text in order for what CommonsWare said to work. Just tried all of this, no inputType before the trial and nothing worked, Enter kept registering as soft enter. After inputType = text, everything including the setImeLabel worked.
Example : android:inputType="text"
final EditText edittext = (EditText) findViewById(R.id.edittext);
edittext.setOnKeyListener(new OnKeyListener() {
public boolean onKey(View v, int keyCode, KeyEvent event) {
// If the event is a key-down event on the "enter" button
if ((event.getAction() == KeyEvent.ACTION_DOWN) &&
(keyCode == KeyEvent.KEYCODE_ENTER)) {
// Perform action on key press
Toast.makeText(HelloFormStuff.this, edittext.getText(), Toast.LENGTH_SHORT).show();
return true;
}
return false;
}
});
Using Kotlin I've made a function that handles all kinds of "done"-like actions for EditText, including the keyboard, and it's possible to modify it and also handle other keys as you wish, too :
private val DEFAULT_ACTIONS_TO_HANDLE_AS_DONE_FOR_EDIT_TEXT = arrayListOf(EditorInfo.IME_ACTION_SEND, EditorInfo.IME_ACTION_GO, EditorInfo.IME_ACTION_SEARCH, EditorInfo.IME_ACTION_DONE)
private val DEFAULT_KEYS_TO_HANDLE_AS_DONE_FOR_EDIT_TEXT = arrayListOf(KeyEvent.KEYCODE_ENTER, KeyEvent.KEYCODE_NUMPAD_ENTER)
fun EditText.setOnDoneListener(function: () -> Unit, onKeyListener: OnKeyListener? = null, onEditorActionListener: TextView.OnEditorActionListener? = null,
actionsToHandle: Collection<Int> = DEFAULT_ACTIONS_TO_HANDLE_AS_DONE_FOR_EDIT_TEXT,
keysToHandle: Collection<Int> = DEFAULT_KEYS_TO_HANDLE_AS_DONE_FOR_EDIT_TEXT) {
setOnEditorActionListener { v, actionId, event ->
if (onEditorActionListener?.onEditorAction(v, actionId, event) == true)
return#setOnEditorActionListener true
if (actionsToHandle.contains(actionId)) {
function.invoke()
return#setOnEditorActionListener true
}
return#setOnEditorActionListener false
}
setOnKeyListener { v, keyCode, event ->
if (onKeyListener?.onKey(v, keyCode, event) == true)
return#setOnKeyListener true
if (event.action == KeyEvent.ACTION_DOWN && keysToHandle.contains(keyCode)) {
function.invoke()
return#setOnKeyListener true
}
return#setOnKeyListener false
}
}
So, sample usage:
editText.setOnDoneListener({
//do something
})
As for changing the label, I think it depends on the keyboard app, and that it usually change only on landscape, as written here. Anyway, example usage for this:
editText.imeOptions = EditorInfo.IME_ACTION_DONE
editText.setImeActionLabel("ASD", editText.imeOptions)
Or, if you want in XML:
<EditText
android:id="#+id/editText" android:layout_width="wrap_content" android:layout_height="wrap_content"
android:imeActionLabel="ZZZ" android:imeOptions="actionDone" />
And the result (shown in landscape) :
Kotlin solution to react to enter press using Lambda expression:
editText.setOnKeyListener { _, keyCode, event ->
if(keyCode == KeyEvent.KEYCODE_ENTER && event.action==KeyEvent.ACTION_DOWN){
//react to enter press here
}
true
}
not doing the additional check for the type of event will cause this listener to be called twice when pressed once (once for ACTION_DOWN, once for ACTION_UP)
A dependable way to respond to an <enter> in an EditText is with a TextWatcher, a LocalBroadcastManager, and a BroadcastReceiver. You need to add the v4 support library to use the LocalBroadcastManager. I use the tutorial at vogella.com: 7.3 "Local broadcast events with LocalBroadcastManager" because of its complete concise code Example. In onTextChanged before is the index of the end of the change before the change>;minus start. When in the TextWatcher the UI thread is busy updating editText's editable, so we send an Intent to wake up the BroadcastReceiver when the UI thread is done updating editText.
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.text.Editable;
//in onCreate:
editText.addTextChangedListener(new TextWatcher() {
public void onTextChanged
(CharSequence s, int start, int before, int count) {
//check if exactly one char was added and it was an <enter>
if (before==0 && count==1 && s.charAt(start)=='\n') {
Intent intent=new Intent("enter")
Integer startInteger=new Integer(start);
intent.putExtra("Start", startInteger.toString()); // Add data
mySendBroadcast(intent);
//in the BroadcastReceiver's onReceive:
int start=Integer.parseInt(intent.getStringExtra("Start"));
editText.getText().replace(start, start+1,""); //remove the <enter>
//respond to the <enter> here
This question hasn't been answered yet with Butterknife
LAYOUT XML
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="#string/some_input_hint">
<android.support.design.widget.TextInputEditText
android:id="#+id/textinput"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:imeOptions="actionSend"
android:inputType="text|textCapSentences|textAutoComplete|textAutoCorrect"/>
</android.support.design.widget.TextInputLayout>
JAVA APP
#OnEditorAction(R.id.textinput)
boolean onEditorAction(int actionId, KeyEvent key){
boolean handled = false;
if (actionId == EditorInfo.IME_ACTION_SEND || (key.getKeyCode() == KeyEvent.KEYCODE_ENTER)) {
//do whatever you want
handled = true;
}
return handled;
}
Replace "txtid" with your EditText ID.
EditText txtinput;
txtinput=findViewById(R.id.txtid)
txtinput.setOnEditorActionListener(new TextView.OnEditorActionListener() {
#Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) || (actionId == EditorInfo.IME_ACTION_DONE)) {
//Code for the action you want to proceed with.
InputMethodManager inputManager = (InputMethodManager)
getSystemService(Context.INPUT_METHOD_SERVICE);
inputManager.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(),
InputMethodManager.HIDE_NOT_ALWAYS);
}
return false;
}
});
Add these depencendy, and it should work:
import android.view.KeyEvent;
import android.view.View;
import android.widget.EditText;
This will give you a callable function when the user presses the return key.
fun EditText.setLineBreakListener(onLineBreak: () -> Unit) {
val lineBreak = "\n"
doOnTextChanged { text, _, _, _ ->
val currentText = text.toString()
// Check if text contains a line break
if (currentText.contains(lineBreak)) {
// Uncommenting the lines below will remove the line break from the string
// and set the cursor back to the end of the line
// val cleanedString = currentText.replace(lineBreak, "")
// setText(cleanedString)
// setSelection(cleanedString.length)
onLineBreak()
}
}
}
Usage
editText.setLineBreakListener {
doSomething()
}
I created a helper class for this by extending the new MaterialAlertDialogBuilder
Usage
new InputPopupBuilder(context)
.setInput(R.string.send,
R.string.enter_your_message,
text -> sendFeedback(text, activity))
.setTitle(R.string.contact_us)
.show();
Code
public class InputPopupBuilder extends MaterialAlertDialogBuilder {
private final Context context;
private final AppCompatEditText input;
public InputPopupBuilder(Context context) {
super(context);
this.context = context;
input = new AppCompatEditText(context);
input.setInputType(InputType.TYPE_CLASS_TEXT);
setView(input);
}
public InputPopupBuilder setInput(int actionLabel, int hint, Callback callback) {
input.setHint(hint);
input.setImeActionLabel(context.getString(actionLabel), KeyEvent.KEYCODE_ENTER);
input.setOnEditorActionListener((TextView.OnEditorActionListener) (v, actionId, event) -> {
if (actionId == EditorInfo.IME_NULL
&& event.getAction() == KeyEvent.ACTION_DOWN) {
Editable text = input.getText();
if (text != null) {
callback.onClick(text.toString());
return true;
}
}
return false;
});
setPositiveButton(actionLabel, (dialog, which) -> {
Editable text = input.getText();
if (text != null) {
callback.onClick(text.toString());
}
});
return this;
}
public InputPopupBuilder setText(String text){
input.setText(text);
return this;
}
public InputPopupBuilder setInputType(int inputType){
input.setInputType(inputType);
return this;
}
public interface Callback {
void onClick(String text);
}
}
Requires
implementation 'com.google.android.material:material:1.3.0-alpha04'
Related
I have written a key listener on a edit text in android.
Following is my code:
textview.setOnKeyListener(new OnKeyListener() {
public boolean onKey(View v, int keyCode, KeyEvent event) {
// If the event is a key-down event on the "enter"
// button
if ((event.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_ENTER)) {
// Perform action on Enter key press
if (textview.getText().toString().length() == 15) {
textvalue = textview.getText().toString();
textview.setText(replacecardformat());
textview.clearFocus();
Log.e(""TAG, "Executed");
return true;
} else {
return false;
}
}
return false;
}
});
However the log statement is executed only once.Is some problem in my return statement.
Two observations:
if you need listener on each text change use view.addTextChangedListener(TextWatcher). Text Watcher has three methods: one fired before, one after, and one on text change. I suppose that this is what you are looking for. More details and tutorial you can find here
is your textview an TextView or EditText? I am asking since only EditText can receive keyboard input. however TextView can have such listener too. Because its text can also change (see documentation here).
How to set these options at the same time :
android:minLines="3"
android:inputType="textMultiLine"
android:imeOptions="actionDone"
It seems as soon as I put android:inputType="textMultiLine", the keyboard automatically replace the key OK by the key Enter. Does anyone know if it is possible to have both keys ?
NB : this answer is not what I am looking for. I would like both keys.
Hi i am also face the same issue finally i got solution for this.
change
android:inputType="textMultiLine"
to
android:inputType="text"
AND
Inside the .java file access EditText using id
editText.setHorizontallyScrolling(false);
editText.setMaxLines(3);
And Now implement the OnEditorAction over the editText.
editText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
#Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if (actionId == 4) { //actionId 4 for actionDone And 6 for actionSend
//perform action what you want
return true;
} else
return false;
}
});
The only thing guaranteed is that Android will pass the inputType and imeOptions to the IME. What the IME does with them is implementation-dependent. Where some IMEs may decide there's sufficient screen real estate to display both keys when in multi-line mode, that behavior shouldn't be relied upon.
Have written an answer here for similar question : https://stackoverflow.com/a/42236407/7550472 and it turned out to be the saving grace for me as nothing else worked. For easier access, i'll paste the code here too for lazy people like me ;).
In your Java code :
////////////Code to Hide SoftKeyboard on Enter (DONE) Press///////////////
editText.setRawInputType(InputType.TYPE_CLASS_TEXT|InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD|InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
editText.setImeActionLabel("DONE",EditorInfo.IME_ACTION_DONE); //Set Return Carriage as "DONE"
editText.setImeOptions(EditorInfo.IME_ACTION_DONE);
editText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
#Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event)
{
if (event == null) {
if (actionId == EditorInfo.IME_ACTION_DONE) {
// Capture soft enters in a singleLine EditText that is the last EditText
// This one is useful for the new list case, when there are no existing ListItems
EditText.clearFocus();
InputMethodManager inputMethodManager = (InputMethodManager) getActivity().getSystemService(Activity.INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(getActivity().getCurrentFocus().getWindowToken(), 0);
}
else if (actionId == EditorInfo.IME_ACTION_NEXT) {
// Capture soft enters in other singleLine EditTexts
} else if (actionId == EditorInfo.IME_ACTION_GO) {
} else {
// Let the system handle all other null KeyEvents
return false;
}
}
else if (actionId == EditorInfo.IME_NULL) {
// Capture most soft enters in multi-line EditTexts and all hard enters;
// They supply a zero actionId and a valid keyEvent rather than
// a non-zero actionId and a null event like the previous cases.
if (event.getAction() == KeyEvent.ACTION_DOWN) {
// We capture the event when the key is first pressed.
} else {
// We consume the event when the key is released.
return true;
}
}
else {
// We let the system handle it when the listener is triggered by something that
// wasn't an enter.
return false;
}
return true;
}
});
The minLines defined in XML will remain the same while the other two attributes are not required as its handled in the Java code.
If you create a subclass of EditText and insert this function, it should solve your problem.
This question was answered at https://stackoverflow.com/a/5037488/7403656 however I made a little alteration which gets the imeOption from the xml instead of just setting it to the Done option.
#Override
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
InputConnection connection = super.onCreateInputConnection(outAttrs);
int imeOptions = getImeOptions();
int imeActions = outAttrs.imeOptions & EditorInfo.IME_MASK_ACTION;
if ((imeActions & imeOptions) != 0) {
// clear the existing action
outAttrs.imeOptions ^= imeActions;
// set the DONE action
outAttrs.imeOptions |= imeOptions;
}
if ((outAttrs.imeOptions & EditorInfo.IME_FLAG_NO_ENTER_ACTION) != 0) {
outAttrs.imeOptions &= ~EditorInfo.IME_FLAG_NO_ENTER_ACTION;
}
return connection;
}
Hello
I've got a searched EditText and search Button. When I type the searched text, I'd like to use ENTER key on softkeyboard instead of search Button to activate search function.
Thanks for help in advance.
You do it by setting a OnKeyListener on your EditText.
Here is a sample from my own code. I have an EditText named addCourseText, which will call the function addCourseFromTextBox when either the enter key or the d-pad is clicked.
addCourseText = (EditText) findViewById(R.id.clEtAddCourse);
addCourseText.setOnKeyListener(new OnKeyListener()
{
public boolean onKey(View v, int keyCode, KeyEvent event)
{
if (event.getAction() == KeyEvent.ACTION_DOWN)
{
switch (keyCode)
{
case KeyEvent.KEYCODE_DPAD_CENTER:
case KeyEvent.KEYCODE_ENTER:
addCourseFromTextBox();
return true;
default:
break;
}
}
return false;
}
});
<EditText
android:id="#+id/search"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:hint="#string/search_hint"
android:inputType="text"
android:imeOptions="actionSend" />
You can then listen for presses on the action button by defining a TextView.OnEditorActionListener for the EditText element. In your listener, respond to the appropriate IME action ID defined in the EditorInfo class, such as IME_ACTION_SEND. For example:
EditText editText = (EditText) findViewById(R.id.search);
editText.setOnEditorActionListener(new OnEditorActionListener() {
#Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
boolean handled = false;
if (actionId == EditorInfo.IME_ACTION_SEND) {
sendMessage();
handled = true;
}
return handled;
}
});
Source: https://developer.android.com/training/keyboard-input/style.html
may be you could add a attribute to your EditText like this:
android:imeOptions="actionSearch"
add an attribute to the EditText like
android:imeOptions="actionSearch"
this is the best way to do the function
and the imeOptions also have some other values like "go" 、"next"、"done" etc.
Most updated way to achieve this is:
Add this to your EditText in XML:
android:imeOptions="actionSearch"
Then in your Activity/Fragment:
EditText.setOnEditorActionListener { _, actionId, _ ->
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
// Do what you want here
return#setOnEditorActionListener true
}
return#setOnEditorActionListener false
}
We can also use Kotlin lambda
editText.setOnKeyListener { _, keyCode, keyEvent ->
if (keyEvent.action == KeyEvent.ACTION_DOWN && keyCode == KeyEvent.KEYCODE_ENTER) {
Log.d("Android view component", "Enter button was pressed")
return#setOnKeyListener true
}
return#setOnKeyListener false
}
To avoid the focus advancing to the next editable field (if you have one) you might want to ignore the key-down events, but handle key-up events. I also prefer to filter first on the keyCode, assuming that it would be marginally more efficient. By the way, remember that returning true means that you have handled the event, so no other listener will. Anyway, here is my version.
ETFind.setOnKeyListener(new OnKeyListener()
{
public boolean onKey(View v, int keyCode, KeyEvent event)
{
if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER
|| keyCode == KeyEvent.KEYCODE_ENTER) {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
// do nothing yet
} else if (event.getAction() == KeyEvent.ACTION_UP) {
findForward();
} // is there any other option here?...
// Regardless of what we did above,
// we do not want to propagate the Enter key up
// since it was our task to handle it.
return true;
} else {
// it is not an Enter key - let others handle the event
return false;
}
}
});
this is a sample of one of my app how i handle
//searching for the Edit Text in the view
final EditText myEditText =(EditText)view.findViewById(R.id.myEditText);
myEditText.setOnKeyListener(new View.OnKeyListener() {
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_DOWN)
if ((keyCode == KeyEvent.KEYCODE_DPAD_CENTER) ||
(keyCode == KeyEvent.KEYCODE_ENTER)) {
//do something
//true because you handle the event
return true;
}
return false;
}
});
how do I catch specific key events from the soft keyboard?
specifically I'm interested in the "Done" key.
I am not quite sure which kind of listener was used in the accepted answer.
I used the OnKeyListener attached to an EditText and it wasn't able to catch next nor done.
However, using OnEditorActionListener worked and it also allowed me to differentiate between them by comparing the action value with defined constants EditorInfo.IME_ACTION_NEXT and EditorInfo.IME_ACTION_DONE.
editText.setOnEditorActionListener(new OnEditorActionListener() {
#Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if ((actionId & EditorInfo.IME_MASK_ACTION) != 0) {
doSomething();
return true;
}
else {
return false;
}
}
});
#Swato's answer wasn't complete for me (and doesn't compile!) so I'm showing how to do the comparison against the DONE and NEXT actions.
editText.setOnEditorActionListener(new OnEditorActionListener() {
#Override
public boolean onEditorAction(TextView view, int actionId, KeyEvent event) {
int result = actionId & EditorInfo.IME_MASK_ACTION;
switch(result) {
case EditorInfo.IME_ACTION_DONE:
// done stuff
break;
case EditorInfo.IME_ACTION_NEXT:
// next stuff
break;
}
}
});
Also I want to point out that for JellyBean and higher OnEditorActionListener is needed to listen for 'enter' or 'next' and you cannot use OnKeyListener. From the docs:
As soft input methods can use multiple and inventive ways of inputting text, there is no guarantee that any key press on a soft keyboard will generate a key event: this is left to the IME's discretion, and in fact sending such events is discouraged. You should never rely on receiving KeyEvents for any key on a soft input method.
Reference: http://developer.android.com/reference/android/view/KeyEvent.html
Note: This answer is old and no longer works. See the answers below.
You catch the KeyEvent and then check its keycode. FLAG_EDITOR_ACTION is used to identify enter keys that are coming from an IME whose enter key has been auto-labelled "next" or "done"
if (event.getKeyCode() == KeyEvent.FLAG_EDITOR_ACTION)
//your code here
Find the docs here.
just do like this :
editText.setOnEditorActionListener(new OnEditorActionListener() {
#Override
public boolean onEditorAction(TextView view, int actionId, KeyEvent event) {
if(actionId == EditorInfo.IME_ACTION_DONE)
{
//Do Something
}
return false;
}
});
etSearchFriends = (EditText) findViewById(R.id.etSearchConn);
etSearchFriends.setOnKeyListener(new OnKeyListener() {
public boolean onKey(View v, int keyCode, KeyEvent event) {
// If the event is a key-down event on the "enter" button
if ((event.getAction() == KeyEvent.ACTION_DOWN) &&
(keyCode == KeyEvent.KEYCODE_ENTER)) {
Toast.makeText(ACTIVITY_NAME.this, etSearchFriends.getText(),Toast.LENGTH_SHORT).show();
return true;
}
return false;
}
});
To catch a “Done” key press from the soft keyboard override Activity's onKeyUp method.
Setting a OnKeyListener listener for a view won't work because key presses in software input methods will generally not trigger the methods of this listener, this callback is invoked when a hardware key is pressed in the view.
// Called when a key was released and not handled by any of the views inside of the activity.
#Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_ENTER:
// code here
break;
default:
return super.onKeyUp(keyCode, event);
}
return true;
}
Note : inputtype mention in your edittext.
<EditText android:id="#+id/select_category"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text" >
edittext.setOnEditorActionListener(new OnEditorActionListener() {
#Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if ((actionId & EditorInfo.IME_MASK_ACTION) == EditorInfo.IME_ACTION_DONE) {
//do something here.
return true;
}
return false;
}
});
you can override done key event by this method:
editText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
#Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if (actionId == EditorInfo.IME_ACTION_DONE) {
// do your stuff here
}
return false;
}
});
KOTLIN version:
<EditText android:id="#+id/edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text" />
Do not forget to set android:inputType.
// Get reference to EditText.
val editText = findViewById<EditText>(R.id.edit_text)
editText.setOnEditorActionListener { _, actionId: Int, _ ->
if (actionId == EditorInfo.IME_ACTION_DONE) {
// Do your logic here.
true
} else {
false
}
}
I have EditText that searches names, and it automatically shows results below in ListView. SoftInput keyboard only showed "next" button and enter sign - which didn't do anything. I wanted only Done button (no next or enter sign) and also I wanted it when it was pressed, it should close keyboard because user should see results below it.
Solution that I found /by Mr Cyril Mottier on his blog/ was very simple and it worked without any additional code:
in xml where EditText is located, this should be written:
android:imeOptions="actionDone"
so hidding keyboard with Done button, EditText should look like this:
<EditText
android:id="#+id/editText1central"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="#+id/imageView1"
android:layout_toLeftOf="#+id/imageView2tie"
android:ems="10"
android:imeOptions="actionDone"
android:hint="#string/trazi"
android:inputType="textPersonName" />
IME_MASK_ACTION is 255, while the received actionId is 6, and my compiler does not accept
if (actionId & EditorInfo.IME_MASK_ACTION)
which is an int. What is the use of &-ing 255 anyway? So the test simply can be
public boolean onEditorAction(TextView view, int actionId, KeyEvent event) {
if (actionId == EditorInfo.IME_ACTION_DONE)
...
I am having an EditText where I am setting the following property so that I can display the done button on the keyboard when user click on the EditText.
editText.setImeOptions(EditorInfo.IME_ACTION_DONE);
When user clicks the done button on the screen keyboard (finished typing) I want to change a RadioButton state.
How can I track done button when it is hit from screen keyboard?
I ended up with a combination of Roberts and chirags answers:
((EditText)findViewById(R.id.search_field)).setOnEditorActionListener(
new EditText.OnEditorActionListener() {
#Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
// Identifier of the action. This will be either the identifier you supplied,
// or EditorInfo.IME_NULL if being called due to the enter key being pressed.
if (actionId == EditorInfo.IME_ACTION_SEARCH
|| actionId == EditorInfo.IME_ACTION_DONE
|| event.getAction() == KeyEvent.ACTION_DOWN
&& event.getKeyCode() == KeyEvent.KEYCODE_ENTER) {
onSearchAction(v);
return true;
}
// Return true if you have consumed the action, else false.
return false;
}
});
Update:
The above code would some times activate the callback twice. Instead I've opted for the following code, which I got from the Google chat clients:
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
// If triggered by an enter key, this is the event; otherwise, this is null.
if (event != null) {
// if shift key is down, then we want to insert the '\n' char in the TextView;
// otherwise, the default action is to send the message.
if (!event.isShiftPressed()) {
if (isPreparedForSending()) {
confirmSendMessageIfNeeded();
}
return true;
}
return false;
}
if (isPreparedForSending()) {
confirmSendMessageIfNeeded();
}
return true;
}
Try this, it should work for what you need:
editText.setOnEditorActionListener(new EditText.OnEditorActionListener() {
#Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if (actionId == EditorInfo.IME_ACTION_DONE) {
//do here your stuff f
return true;
}
return false;
}
});
<EditText android:imeOptions="actionDone"
android:inputType="text"/>
The Java code is:
edittext.setOnEditorActionListener(new OnEditorActionListener() {
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if (actionId == EditorInfo.IME_ACTION_DONE) {
Log.i(TAG,"Here you can write the code");
return true;
}
return false;
}
});
Kotlin Solution
The base way to handle it in Kotlin is:
edittext.setOnEditorActionListener { _, actionId, _ ->
if (actionId == EditorInfo.IME_ACTION_DONE) {
callback.invoke()
return#setOnEditorActionListener true
}
false
}
Kotlin Extension
Use this to just call edittext.onDone{/*action*/} in your main code. Makes your code far more readable and maintainable
fun EditText.onDone(callback: () -> Unit) {
setOnEditorActionListener { _, actionId, _ ->
if (actionId == EditorInfo.IME_ACTION_DONE) {
callback.invoke()
return#setOnEditorActionListener true
}
false
}
}
Don't forget to add these options to your edittext
<EditText ...
android:imeOptions="actionDone"
android:inputType="text"/>
If you need inputType="textMultiLine" support, read this post
I know this question is old, but I want to point out what worked for me.
I tried using the sample code from the Android Developers website (shown below), but it didn't work. So I checked the EditorInfo class, and I realized that the IME_ACTION_SEND integer value was specified as 0x00000004.
Sample code from Android Developers:
editTextEmail = (EditText) findViewById(R.id.editTextEmail);
editTextEmail
.setOnEditorActionListener(new OnEditorActionListener() {
#Override
public boolean onEditorAction(TextView v, int actionId,
KeyEvent event) {
boolean handled = false;
if (actionId == EditorInfo.IME_ACTION_SEND) {
/* handle action here */
handled = true;
}
return handled;
}
});
So, I added the integer value to my res/values/integers.xml file.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<integer name="send">0x00000004</integer>
</resources>
Then, I edited my layout file res/layouts/activity_home.xml as follows
<EditText android:id="#+id/editTextEmail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:imeActionId="#integer/send"
android:imeActionLabel="#+string/send_label"
android:imeOptions="actionSend"
android:inputType="textEmailAddress"/>
And then, the sample code worked.
More details on how to set the OnKeyListener, and have it listen for the Done button.
First add OnKeyListener to the implements section of your class. Then add the function defined in the OnKeyListener interface:
/*
* Respond to soft keyboard events, look for the DONE press on the password field.
*/
public boolean onKey(View v, int keyCode, KeyEvent event)
{
if ((event.getAction() == KeyEvent.ACTION_DOWN) &&
(keyCode == KeyEvent.KEYCODE_ENTER))
{
// Done pressed! Do something here.
}
// Returning false allows other listeners to react to the press.
return false;
}
Given an EditText object:
EditText textField = (EditText)findViewById(R.id.MyEditText);
textField.setOnKeyListener(this);
While most people have answered the question directly, I wanted to elaborate more on the concept behind it. First, I was drawn to the attention of IME when I created a default Login Activity. It generated some code for me which included the following:
<EditText
android:id="#+id/password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="#string/prompt_password"
android:imeActionId="#+id/login"
android:imeActionLabel="#string/action_sign_in_short"
android:imeOptions="actionUnspecified"
android:inputType="textPassword"
android:maxLines="1"
android:singleLine="true"/>
You should already be familiar with the inputType attribute. This just informs Android the type of text expected such as an email address, password or phone number. The full list of possible values can be found here.
It was, however, the attribute imeOptions="actionUnspecified" that I didn't understand its purpose. Android allows you to interact with the keyboard that pops up from bottom of screen when text is selected using the InputMethodManager. On the bottom corner of the keyboard, there is a button, typically it says "Next" or "Done", depending on the current text field. Android allows you to customize this using android:imeOptions. You can specify a "Send" button or "Next" button. The full list can be found here.
With that, you can then listen for presses on the action button by defining a TextView.OnEditorActionListener for the EditText element. As in your example:
editText.setOnEditorActionListener(new EditText.OnEditorActionListener() {
#Override
public boolean onEditorAction(EditText v, int actionId, KeyEvent event) {
if (actionId == EditorInfo.IME_ACTION_DONE) {
//do here your stuff f
return true;
}
return false;
}
});
Now in my example I had android:imeOptions="actionUnspecified" attribute. This is useful when you want to try to login a user when they press the enter key. In your Activity, you can detect this tag and then attempt the login:
mPasswordView = (EditText) findViewById(R.id.password);
mPasswordView.setOnEditorActionListener(new TextView.OnEditorActionListener() {
#Override
public boolean onEditorAction(TextView textView, int id, KeyEvent keyEvent) {
if (id == R.id.login || id == EditorInfo.IME_NULL) {
attemptLogin();
return true;
}
return false;
}
});
Thanks to chikka.anddev and Alex Cohn in Kotlin it is:
text.setOnEditorActionListener { v, actionId, event ->
if (actionId == EditorInfo.IME_ACTION_DONE ||
event?.action == KeyEvent.ACTION_DOWN && event.keyCode == KeyEvent.KEYCODE_ENTER) {
doSomething()
true
} else {
false
}
}
Here I check for Enter key, because it returns EditorInfo.IME_NULL instead of IME_ACTION_DONE.
See also Android imeOptions="actionDone" not working. Add android:singleLine="true" in the EditText.
If you use Android Annotations
https://github.com/androidannotations/androidannotations
You can use #EditorAction annotation
#EditorAction(R.id.your_component_id)
void onDoneAction(EditText view, int actionId){
if(actionId == EditorInfo.IME_ACTION_DONE){
//Todo: Do your work or call a method
}
}