I have a custom dialog which is a DialogFragment. This dialog have a EditText and my own keyboard view so I don't want to use the default virtual keyboard.
I hide the virtual keyboard everytime user touch the EditText:
edtAmount.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
v.onTouchEvent(event);
View view = this.getDialog().getCurrentFocus();
if (view != null) {
InputMethodManager imm = (InputMethodManager) getActivity()
.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(view.getWindowToken(),0);
}
return true;
}
});
But because the system still call the virtual keyboard to show (Before is force to hide it), then system move my dialog up and down very quickly. This is not good.
Can someone help me to avoid the dialog pushed up like this, just keep it stay still?
PS: I tried in Manifest:
android:windowSoftInputMode="adjustNothing"
But seem like not work.
Thank you very much.
EDIT
I want to keep the cursor so I find the solution in this thread:
https://stackoverflow.com/a/14184958/2961402
Hope this help some one.
This can only done when you extends the EditText from your custom EditText, please use the below code for custom EditText which never open Soft Keyboard ever...!
public class DisableSoftKeyBoardEditText extends EditText {
public DisableSoftKeyBoardEditText(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public boolean onCheckIsTextEditor() {
return false;
}
}
Try this code. In my app it work perfectly
getActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
1) make 2 Edit Text fields close to the bottom of the screen, also a submit button (on submit have a setError called on the first field)
2) run the app, enter some text in both fields, hit submit
3) you should see the error popup in the correct position (as expected), click into the 2nd text field, then click back into the first text field, the error popup is off-position (it's either not aligned correctly or the arrow is flipped in the wrong direction). While the soft keyboard is up in this case you can also hit back to close the soft keyboard but the error popup is still off-positioned.
Add this class to your source folder.
public class ListenerEditText extends EditText {
private KeyImeChange keyImeChangeListener;
public ListenerEditText(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void setKeyImeChangeListener(KeyImeChange listener){
keyImeChangeListener = listener;
}
public interface KeyImeChange {
public void onKeyIme(int keyCode, KeyEvent event);
}
#Override
public boolean onKeyPreIme (int keyCode, KeyEvent event){
if(keyImeChangeListener != null){
keyImeChangeListener.onKeyIme(keyCode, event);
}
return false;
}
}
In your XML file.
<com.src.ListenerEditText
android:id="#+id/password"
style="#style/EditBoxStyle"
android:ems="30"
android:hint="*API Key"
android:inputType="text|textNoSuggestions"
android:maxLength="250"
android:singleLine="true"
</com.src.ListenerEditText>
Add action for edittext.
password.setKeyImeChangeListener(new KeyImeChange() {
#Override
public void onKeyIme(int keyCode, KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
password.clearFocus();
}
}
});
So I have an Activity that is using windowSoftInputMode="adjustPan", and I have a OnPreDrawListener for an EditText that calls:
editText.requestFocus();
inputManager.showSoftInput(editText, 0);
Which works as expected and pushes the Activity up to make room for the EditText. However, if I dismiss the keyboard with the back button (which pans the window back to the original location), then touch the EditText again to show the keyboard, the keyboard shows, but the window does not adjust.
I've even tried adding an OnClickListener to the EditText and calling the same two calls again:
editText.requestFocus();
inputManager.showSoftInput(editText, 0);
But the window does not pan until I dismiss the window and show it again. Any suggestions?
I think this three steps will solve your problem.
1)in manifest file change windowSoftInputMode="adjustPan"
to windowSoftInputMode="adjustResize"
2) The layout you are using for EditText , tha change the parent layout to ScroolView.
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/android:list"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<EditText
android:id="#+id/edittextview"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:inputType="textFilter"
android:padding="10dp"
android:imeOptions="actionDone"
android:scrollbars="vertical"
android:textSize="14sp" />
</ScrollView>
3) To explicitly showing keyboard to avoid "dismiss the keyboard with the back button and window is not Adjust"
in Edittext onclick write
edittext.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
InputMethodManager m = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
if (m != null) {
m.toggleSoftInput(0, InputMethodManager.SHOW_IMPLICIT);
edittext.requestFocus();
}
}
});
Hope this will solve your problem.
So it's not exactly a solution to the problem, but it's the workaround I ended up going with. I created a subclass of LinearLayout to intercept the back button press before the IME receives it:
public class IMEInterceptLinearLayout extends LinearLayout {
//For some reason, the event seems to occur twice for every back press
//so track state to avoid firing multiple times
private boolean notifiedListener = false;
private OnBackPressedPreIMEListener listener;
public IMEInterceptLinearLayout(Context context) {
super(context);
}
public IMEInterceptLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public IMEInterceptLinearLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public void setOnBackPressedPreIMEListener(OnBackPressedPreIMEListener listener) {
this.listener = listener;
}
private void fireOnBackPressedPreIME() {
if(listener != null && !notifiedListener) {
listener.onBackPressedPreIME();
notifiedListener = true;
}
}
#Override
public boolean dispatchKeyEventPreIme(KeyEvent event) {
if(event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
fireOnBackPressedPreIME();
return true;
} else return super.dispatchKeyEventPreIme(event);
}
public interface OnBackPressedPreIMEListener {
public void onBackPressedPreIME();
}
}
Then from there I just registered my window as a listener for the layout, and dismiss the window and the keyboard when I receive the event, disallowing the keyboard to be dismissed while the window is visible.
How do I turn off the IME-functionality of an EditText?
Or: How do I avoid the display of the IME-keyboard?
I have a layout where my special keyboard sits below the EditText so there's no need to show the IME. Please understand that I cannot implement my keyboard as IME as it is specific for this very EditText and using it in any other context would only cause problems.
I tried to use
getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
in the onCreate() of the activity, but that doesn't seem to do anything in this situation.
Think I found a way to do it... subclass EditText and override onCheckIsTextEditor() to return false:
public class EditTextEx extends EditText {
public EditTextEx(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public boolean onCheckIsTextEditor() {
return false;
}
}
I've tested it and I can't get the soft keyboard to show at all.
editText.setInputType(EditorInfo.TYPE_NULL);
While trying to get it working I also tried:
inputField.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
}
});
inputField.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent event) {
getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
return false;
}
});
Both get called, but neither hide the IME-pop-up.
Is it possible to have an EditText widget with android:inputType="textMultiLine" set, and android:imeOptions="actionDone" at the same time?
I'd like a multi-line edit box, with the action button on the keyboard to be Done, not Enter (Carriage Return), but it doesn't seem to be working.
Use
editText.setImeOptions(EditorInfo.IME_ACTION_DONE);
editText.setRawInputType(InputType.TYPE_CLASS_TEXT);
and in XML:
android:inputType="textMultiLine"
From the android documentation: '"textMultiLine"
Normal text keyboard that allow users to input long strings of text that include line breaks (carriage returns).' Therefore the textMultiLine attribute is not appropriate if you want to have the 'Done' button in the keyboard.
A simple way to get a multi-line (in this case 3 lines) input field with the done button is to use EditText with
android:lines="3"
android:scrollHorizontally="false"
However, for some reason this only works for me if I do these settings in the code instead of the layout file (in onCreate) by
TextView tv = (TextView)findViewById(R.id.editText);
if (tv != null) {
tv.setHorizontallyScrolling(false);
tv.setLines(3);
}
I hope this helps someone, as it took quite a while to figure out. If you find a way to make it work from the manifest, please let us know.
Working Example!
Create the below custom EditText class that supports this feature and use the class in the xml file. Working code:
package com.example;
import android.content.Context;
import android.util.AttributeSet;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import android.widget.EditText;
public class ActionEditText extends EditText
{
public ActionEditText(Context context)
{
super(context);
}
public ActionEditText(Context context, AttributeSet attrs)
{
super(context, attrs);
}
public ActionEditText(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
}
#Override
public InputConnection onCreateInputConnection(EditorInfo outAttrs)
{
InputConnection conn = super.onCreateInputConnection(outAttrs);
outAttrs.imeOptions &= ~EditorInfo.IME_FLAG_NO_ENTER_ACTION;
return conn;
}
}
<com.example.ActionEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:imeOptions="actionDone"
android:inputType="textAutoCorrect|textCapSentences|textMultiLine" />
To do this in Kotlin (and also optionally apply other configurations like textCapSentences you can use this extension function:
// To use this, do NOT set inputType on the EditText in the layout
fun EditText.setMultiLineCapSentencesAndDoneAction() {
imeOptions = EditorInfo.IME_ACTION_DONE
setRawInputType(InputType.TYPE_TEXT_FLAG_CAP_SENTENCES or InputType.TYPE_TEXT_FLAG_MULTI_LINE)
}
Usage:
myEditText.setMultiLineCapSentencesAndDoneAction()
Reuseable Kotlin Solution
Setting these values in code was the only thing that worked for me
edittext.inputType = EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE
edittext.setHorizontallyScrolling(false)
edittext.maxLines = Integer.MAX_VALUE // Or your preferred fixed value
I require this frequently, so made this to keep the code clean:
fun EditText.multilineIme(action: Int) {
imeOptions = action
inputType = EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE
setHorizontallyScrolling(false)
maxLines = Integer.MAX_VALUE
}
// Then just call
edittext.multilineIme(EditorInfo.IME_ACTION_DONE)
If you want to be add an optional custom action on 'Done', try this:
fun EditText.multilineDone(callback: (() -> Unit)? = null) {
val action = EditorInfo.IME_ACTION_DONE
multilineIme(action)
setOnEditorActionListener { _, actionId, _ ->
if (action == actionId) {
callback?.invoke()
true
}
false
}
}
}
// Then you can call
edittext.multilineDone { closeKeyboard() }
// or just
edittext.multilineDone()
Need to easily control the keyboard in callback? Read this post
Then add hideKeyboard() call in EditText.multilineDone
I think this is the way to do you thing. Having android:inputType="textMultiLine", android:imeOptions="actionDone" makes enter key functionality ambiguous. Just keep in mind that you can use android:lines="10" and maybe remove android:inputType="textMultiLine", but depends what you want to achieve sometimes you just need the android:inputType="textMultiLine" and there is no replacement for it.
EditText ed=new EditText(this);
ed.setOnKeyListener(new OnKeyListener() {
#Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if(keyCode == KeyEvent.KEYCODE_ENTER){
//do your stuff here
}
return false;
}
});
This seems to work for me perfectly
int lineNum = 2;
mEditText.setHorizontallyScrolling(false);
mEditText.setLines(3);
Short answer: No, I believe it's not possible prior to API level 11 (3.0).
The same issue cropped up here (discussed in the comments to the accepted answer):
Android Soft keyboard action button
From the final comment:
Looking at a few apps on my phone, it seems common to have the multiline box last, with a visible "Done" or "Send" button below it (e.g. Email app).
A simple way to work around this situation:
keep this attributes on the EditText:
android:inputType="textMultiLine"
android:scrollHorizontally="false"
then add this code to only hide the keyboard when ENTER is pressed:
editText.setOnEditorActionListener(new OnEditorActionListener()
{
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_ENTER)
{
editText.setSelection(0);
InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(editText.getWindowToken(), 0);
return true;
}
else
{
return false;
}
}
});
If it is not about the look of the on-screen keyboard, you could simply put a input listener on the keyboard and fire the "done"-status if the user inputs a newline.
if you use the input option textImeMultiline with imeoptions flagnext and actionnext you get a next button instead of the cariage return
While none of the other solutions ever worked for me, the following worked beautifully and saved me days and days of more googling, with a few twists of my own of course. Unfortunately don't remember where I got the code from exactly and so cannot give the author the credit he/she so deserves.
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;
}
});
I'm on 4.x and tried calling setHorizontallyScrolling() (with or without setLine() or setMaxLines()), as well as many different XML configurations to get the Done button to show. None of them worked. The bottom line is that if your EditText is multi-line, Android will always want to show the carriage return instead of the "Done" button, unless you put in some hack around this.
The least complication solution I found that doesn't involve remapping the behavior of the carriage return is here: https://stackoverflow.com/a/12570003/3268329. This solution will nullify Android relentless desire to force setting of the IME_FLAG_NO_ENTER_ACTION flag for multi-line views, which causes the Done button to disappear.
I struggled as well for quite some time, but i finally found a solution!
Just create a custom EditText class as such :
public class EditTextImeMultiline extends EditText {
public void init() {
addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
#Override
public void afterTextChanged(Editable s) {
for (int i = s.length(); i > 0; i--)
if (s.subSequence(i - 1, i).toString().equals("\n"))
s.replace(i - 1, i, "");
}
});
setSingleLine();
setHorizontallyScrolling(false);
this.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
EditTextImeMultiline.this.setLines(EditTextImeMultiline.this.getLineCount());
}
});
}
public EditTextImeMultiline(Context context) {
super(context);
init();
}
public EditTextImeMultiline(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public EditTextImeMultiline(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public EditTextImeMultiline(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
}
This class removes lineBreaks (\n), wraps the text as textMultiline would do, AND allows you to replace the Enter button by a ImeAction ;).
You just need to call it in your XML instead of the classic EditText class.
To explain the logic here :
Set the EditText as a singleLine to be able to show a ImeAction button instead of Enter.
Remove the horizontal scrolling to make the text go to the next line when reaching the end of the view.
Watch the layout changes with the onGlobalLayoutListener, and set it's "line" parameter to the "lineCount" of the current text held by the editText. This is what refreshes its height.
Working solution is here, create your custom EditTextView (just extend a textview) and override onInputConnection wit a piece of code youll find in accepted answer here: Multiline EditText with Done SoftInput Action Label on 2.3
If you use DataBinding, you should create a method that will catch actions. See also https://stackoverflow.com/a/52902266/2914140.
Some file with extension methods, for instance, BindingAdapters.kt:
#BindingAdapter("inputType", "action")
fun EditText.setMultiLineCapSentencesAndDoneAction(inputType: Int, callback: OnActionListener?) {
setRawInputType(inputType)
if (callback == null) setOnEditorActionListener(null)
else setOnEditorActionListener { v, actionId, event ->
if (actionId == EditorInfo.IME_ACTION_DONE ||
event?.keyCode == KeyEvent.KEYCODE_ENTER && event.action == KeyEvent.ACTION_DOWN
) {
callback.enterPressed()
return#setOnEditorActionListener true
}
return#setOnEditorActionListener false
}
}
interface OnActionListener {
fun enterPressed()
}
Then in XML:
<data>
<variable
name="viewModel"
type="YourViewModel" />
<import type="android.text.InputType" />
</data>
<EditText
android:imeOptions="actionDone"
android:inputType=""
app:action="#{() -> viewModel.send()}"
app:inputType="#{InputType.TYPE_TEXT_FLAG_CAP_SENTENCES | InputType.TYPE_TEXT_FLAG_MULTI_LINE}" />
For Compose UI the code is:
TextField(
...
keyboardOptions = KeyboardOptions(
imeAction = ImeAction.Done
),
...
)