AutoCompleteTextView: Remove soft keyboard on back press instead of suggestions - android

When using AutoCompleteTextView, the dropdown suggestion list appears with the software keyboard still visible. This makes sense, as it is often a lot more efficient to type ensuing characters to narrow the list.
But if the user wants to navigate the suggestion list, it becomes extremely tedious with the software keyboard still up (this is even more of a problem when the device is in landscape orientation). Navigating the list is a lot easier without the keyboard hogging the screen space. Unfortunately, the default behaviour removes the list first when you press the back key (even though in the software versions of the back key it is showing the image that says 'pressing this will hide the keyboard').
Here's a barebones example that demonstrates what I'm talking about:
public class Main2 extends Activity {
private static final String[] items = {
"One",
"Two",
"Three",
"Four",
"Five"
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AutoCompleteTextView actv = new AutoCompleteTextView(this);
actv.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
actv.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, items));
actv.setThreshold(1);
LinearLayout ll = new LinearLayout(this);
ll.setOrientation(LinearLayout.VERTICAL);
ll.addView(actv);
setContentView(ll);
}
}
Besides the fact that this is unintuitive (the back key hint is suggesting that the back press will be sent to the keyboard), it makes navigating AutoCompleteTextView suggestions extremely tiresome.
What is the least intrusive way (e.g. catching the back in on onBackPressed() in every activity and routing it accordingly would definitely not be ideal) to make the first back press hide the keyboard, and the second remove the suggestion list?

You can achieve that by override-ing onKeyPreIme in your custom AutoCompleteTextView.
public class CustomAutoCompleteTextView extends AutoCompleteTextView {
public CustomAutoCompleteTextView(Context context) {
super(context);
}
public CustomAutoCompleteTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomAutoCompleteTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && isPopupShowing()) {
InputMethodManager inputManager = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
if (inputManager.hideSoftInputFromWindow(findFocus().getWindowToken(),
InputMethodManager.HIDE_NOT_ALWAYS)) {
return true;
}
}
return super.onKeyPreIme(keyCode, event);
}
}

set DismissClickListener like this
autoCompleteTextView.setOnDismissListener(new AutoCompleteTextView.OnDismissListener() {
#Override
public void onDismiss() {
InputMethodManager in = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
in.hideSoftInputFromWindow(getCurrentFocus().getApplicationWindowToken(), 0);
}
});

Related

Edittext cursor still blinks after closing the soft keyboard

Is an edittext cursor supposed to continue blinking after the soft keyboard is closed or is this a result of testing on an emulator and wouldn't happen on an actual device? -- as pointed out by the second post in this discussion
Update:
I know that the edittexts still have the cursor blinking because they're still in focus -- logged a message whenever edittext lost focus, but message was never logged when soft keyboard closed.
Update:
I've tried doing:
#Override
public void onBackPressed() {
super.onBackPressed();
getCurrentFocus().clearFocus();
}
So that every time the keyboard is closed, the EditText currently in focus loses that focus and onFocusChanged() is called. The problem is that onBackPressed() isn't called when the back button is pressed when the keyboard is up. I know this because I put a toast in onBackPressed(), and no toast shows when the back button is pressed whilst the keyboard is up.
First create a custom Edit text. Below is the example which has a call back when keyboard back is pressed to dismiss the keyboard
public class EdittextListner extends EditText {
private KeyImeChange keyImeChangeListener;
public EdittextListner(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void setKeyImeChangeListener(KeyImeChange listener) {
keyImeChangeListener = listener;
}
public interface KeyImeChange {
public boolean onKeyIme(int keyCode, KeyEvent event);
}
#Override
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
if (keyImeChangeListener != null) {
return keyImeChangeListener.onKeyIme(keyCode, event);
}
return false;
}
}
Secondly change your EditText to EdittextListner in you layout file.
Finally do the following
mLastNameEditText.setKeyImeChangeListener(new EdittextListner.KeyImeChange() {
#Override
public boolean onKeyIme(int keyCode, KeyEvent event) {
mLastNameEditText.clearFocus();
return true;
}
});
This worked for me. Hope this helps
Edittext is a View which accept input from user, so it is not related with keyborad open or close, when user will click on edittext, that edittext will get focus and cursor will start to blink for taking input,
So you can do one thing as when you are closing keyboard at the same time you can also set visibility of cursor for that edittext so it will stop to blink,
For that you need to write below line when you hide keyboard.
editTextObject.setCursorVisible(false);
This will stope cursor to blink.
As you said, the blinking cursor in the EditText is related to the EditText having focus, but showing or hiding the soft keyboard has no correlation to a View gaining or losing focus. Any View (EditText or otherwise) can be focused independent of whether or not a soft keyboard is showing and there is nothing intrinsic to EditText that would make it behave any differently.
If you want an EditText to lose focus whenever the soft keyboard is hidden, you will need to implement this functionality yourself by listening for changes in the soft keyboard visibility and updating the EditText as a result.
The only way to know keyboard is disappeared is to override
OnglobalLayout and check the height.
Based on that event you can "setCursorVisible(false)" on your edit text
For more information, check this Link.
RelativeLayout mainLayout = findViewById(R.layout.main_layout); // You must use the layout root
InputMethodManager im = (InputMethodManager) getSystemService(Service.INPUT_METHOD_SERVICE);
/*
Instantiate and pass a callback
*/
SoftKeyboard softKeyboard;
softKeyboard = new SoftKeyboard(mainLayout, im);
softKeyboard.setSoftKeyboardCallback(new SoftKeyboard.SoftKeyboardChanged()
{
#Override
public void onSoftKeyboardHide()
{
// Code here
EditText.clearFocus();
}
#Override
public void onSoftKeyboardShow()
{
// Code here
}
});
/*
Open or close the soft keyboard easily
*/
softKeyboard.openSoftKeyboard();
softKeyboard.closeSoftKeyboard();
/* Prevent memory leaks:
*/
#Override
public void onDestroy()
{
super.onDestroy();
softKeyboard.unRegisterSoftKeyboardCallback();
}
try this:
public class EditTextBackEvent extends EditText {
private EditTextImeBackListener mOnImeBack;
public EditTextBackEvent(Context context) {
super(context);
}
public EditTextBackEvent(Context context, AttributeSet attrs) {
super(context, attrs);
}
public EditTextBackEvent(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) {
if (mOnImeBack != null) mOnImeBack.onImeBack(this, this.getText().toString());
}
return super.dispatchKeyEvent(event);
}
public void setOnEditTextImeBackListener(EditTextImeBackListener listener) {
mOnImeBack = listener;
}
public interface EditTextImeBackListener {
void onImeBack(EditTextBackEvent ctrl, String text);
}
}
in your layout:
<yourpackagename.EditTextBackEvent
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
and in your fragment:
edittext.setOnEditTextImeBackListener(new EditTextBackEvent.EditTextImeBackListener()
{
#Override
public void onImeBack(EditTextBackEvent ctrl, String text)
{
edittext.clearfocus();
}
});
Try keeping a view in your layout which is focusable above your editText.
<View
android:layout_width="0dp"
android:layout_height="0dp"
android:focusable="true"
android:focusableInTouchMode="true" />
This should work as the blank focusable view should catch focus and not your edittext.

Skipping disabled EditText's when pressing Next IME button on soft keyboard

I have a LinearLayout with several EditText's, all of them created programmatically (not with an XML layout), and in particular without IDs.
When I'm typing in one of the EditText's, and the next one (respective to focus) is disabled, and I press the Next IME button on the keyboard, the focus advances to the disabled EditText, but I can't type anything in it.
What I was expecting was focus to advance to the next enabled EditText. I also tried, in addition to making the EditText disabled via edittext.setEnabled(false), to disable its focusability via edittext.setFocusable(false) and edittext.setFocusableInTouchMode(false), and to set a TYPE_NULL input type, but to no avail.
Any hints?
Thanks ;)
Solved by examining how the next focusable is found by the keyboard from this blog post and by subclassing EditText:
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.EditText;
public class MyEditText extends EditText {
public MyEditText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public MyEditText(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyEditText(Context context) {
super(context);
}
#Override
public View focusSearch(int direction) {
View v = super.focusSearch(direction);
if (v != null) {
if (v.isEnabled()) {
return v;
} else {
// keep searching
return v.focusSearch(direction);
}
}
return v;
}
}
More details:
ViewGroup implementation of focusSearch() uses a FocusFinder, which invokes addFocusables(). The ViewGroup's implementation tests for visibility, while the View implementation tests for focusability. Neither test for the enabled state, which is why I added this test to MyEditText above.
I solved it setting the focusable property to false, not only the enabled property:
editText.setEnabled(false);
editText.setFocusable(false);
See
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;
}
});
This was grabbed from http://developer.android.com/training/keyboard-input/style.html#Action .
If you can figure out how to focus on the next TextView, you can add an OnEditorActionListener to every TextView and have it pass the focus to the next one if it is disabled.

Showing the Soft Keyboard manually with InputMethodManager does not adjust the window

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.

Android custom EditText and back button override

I want to override the back button when the soft keyboard is shown. Basically when the back button is hit, I want the keyboard to dismiss, and I want to append some text onto whatever the user has typed in that edit text field. So basically I need to know when the keyboard is dismissed. After searching around, I realized there is no API for this, and that the only real way to do this would be to make your EditText class.
So I created my own EditText class and extended EditText like this
public class CustomEditText extends EditText
{
public CustomEditText(Context context)
{
super(context);
init();
}
public CustomEditText(Context context, AttributeSet attrs)
{
super(context, attrs);
init();
}
public CustomEditText(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
init();
}
private void init()
{
}
}
I have also added this method
#Override
public boolean dispatchKeyEventPreIme(KeyEvent event)
{
if (KeyEvent.KEYCODE_BACK == event.getKeyCode())
{
Log.v("", "Back Pressed");
//Want to call this method which will append text
//init();
}
return super.dispatchKeyEventPreIme(event);
}
Now this method does override the back button, it closes the keyboard, but I dont know how I would pass text into the EditText field. Does anyone know how I would do this?
Also another quick question, does anyone know why this method is called twice? As you can see for the time being, I have added a quick logcat message to test it works, but when I hit the back button, it prints it twice, any reason why it would be doing this?
Any help would be much appreciated!!
This is due to the dispatchKeyEventPreIme being called on both ACTION_DOWN and ACTION_UP.
You will have to process only when KEY down is pressed. So use
if(event.getAction () == KeyEvent.ACTION_DOWN)
Edit:
for the first question You could do
setText(getText().toString() + " whatever you want to append");
in dispatchKeyEventPreIme
Why twice? Probably the method is called on press down and up event.

Multi-line EditText with Done action button

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
),
...
)

Categories

Resources