127

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.

SecretAgentMan
  • 2,690
  • 6
  • 16
  • 35
kefs
  • 3,416
  • 4
  • 19
  • 25

15 Answers15

219

Use

editText.setImeOptions(EditorInfo.IME_ACTION_DONE);
editText.setRawInputType(InputType.TYPE_CLASS_TEXT);

and in XML:

android:inputType="textMultiLine"
FelixSFD
  • 5,456
  • 10
  • 40
  • 106
alexbtr
  • 2,646
  • 1
  • 9
  • 16
  • for me the cursor would still show when the keyboard went down, i needed to add `textField.setCursorVisible(false);` inside an `onEditorActionListener` – Fonix Sep 22 '17 at 14:35
  • Works on 4.2.2 and 7.1.1. Thanks. – tehcpu Feb 03 '18 at 10:37
  • 1
    Works very well... I struggled to find it. This answer should be marked as best answer – MFAL Feb 06 '18 at 16:43
  • 8
    why does this work as opposed to setting it all up in xml? – Andrew Steinmetz Feb 27 '18 at 10:26
  • @AndrewSteinmetz I think that's because you cannot set `rawInputType` using xml – Omar Hezi Feb 22 '19 at 13:23
  • Have been looking for this logic for a long time, thank you! @AndrewSteinmetz setting multiline in the xml overrides the xml description of the other permissions you need set, so doing this all in xml would not give the same results as with the above java code. – ogoldbart3 Dec 10 '19 at 02:23
  • 1
    Struggled abit to find this info. It is still working like a charm! – Costin Jan 15 '20 at 09:53
  • I also had the issue with the cursor remaining active, but I resolved it using `clearFocus()` in an `onEditorActionListener`. I also had to make sure the listener always returned `false` to keep it from breaking the done behaviour. – SkeletorFromEterenia Jan 15 '20 at 15:38
  • 1
    just the rawInputType needed programmatically, you can still set the imeOptions `actionDone` from xml – hmac Feb 24 '20 at 09:42
  • Greatly worked with AutoCompletTextView and with actionNEXT! The key was the setRawInputType(InputType.TYPE_CLASS_TEXT). The other two parameters i setted earlyer in my XML but does not worked whitout the setRawInpuType. Thank you the solution! – Abigail La'Fay Dec 17 '20 at 01:49
  • You can use data binding to set rawInputType from XML as well: `@BindingAdapter("rawInputType") fun setRawInputType(view: EditText, inputType: Int) { view.setRawInputType(inputType) }`. Then in the data section of your layout XML: `` and in your EditText `app:rawInputType="@{InputType.TYPE_CLASS_TEXT}"`. – ubuntudroid Apr 14 '21 at 18:26
52

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.

Robb1
  • 3,075
  • 5
  • 21
  • 49
HYS
  • 762
  • 6
  • 10
  • 4
    I would also suggest trying `maxLines()` instead of `setLines()` if you want to avoid changing the height of the `EditText` – Daniel Smith Jan 21 '14 at 22:50
  • I think that in the question it is not clarified that you should set android:imeOptions with a value such as actionSend. Completing this answer, I had to set android:singleLine="true" even if the setMaxLines sort of overwrites it by code (not doing so won't give you an enter key with e.g. "Send"). To capture the action, check the first answer from http://stackoverflow.com/questions/5014219/multiline-edittext-with-done-softinput-action-label-on-2-3 out. – DNax Dec 01 '14 at 19:38
  • Sorry, the best alternative I found about capturing the is @earlcasper answer here http://stackoverflow.com/questions/1489852/android-handle-enter-in-an-edittext – DNax Dec 02 '14 at 19:26
  • 1
    This worked perfectly for me (using `setMaxLines(3)`) Thanks a lot! – laurencevs Jan 02 '16 at 02:35
  • Worked for me, using `setMaxLines()` and leaving `lines` equal to 1. Thanks a ton! – Dooskington Oct 29 '16 at 21:35
  • 1
    Worked like a charm: just add android:imeOptions="actionDone" android:inputType="text" to your XML as well and remove android:lines="3" android:scrollHorizontally="false" from XML – HannahCarney Nov 22 '16 at 14:31
27

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" />
Anees U
  • 1,047
  • 1
  • 11
  • 17
  • This worked for me my requirement was to make a edit text which should be multi line as well as should have next button on the soft keys ...............so thanks a lot what i did was in edit text i added 2 lines android:inputType="textMultiLine" android:imeOptions="actionNext" And in the custom class above i did: InputConnection conn = super.onCreateInputConnection(outAttrs); //outAttrs.imeOptions &= ~EditorInfo.IME_FLAG_NO_ENTER_ACTION; outAttrs.imeOptions &= EditorInfo.IME_ACTION_NEXT; return conn; – yash Aug 19 '16 at 12:35
  • Works. Tested on Andorid 6.0.1. – AmiguelS Feb 14 '17 at 15:06
13

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()
Ollie C
  • 27,184
  • 33
  • 125
  • 211
10

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;
        }
});
Sasi Kanth
  • 629
  • 8
  • 15
Lukap
  • 29,596
  • 60
  • 146
  • 239
  • 1
    Using a fixed amount of max numbers with **android:lines="10"** worked for me, getting the ok button on the keyboard. Good trick if one knows how many lines there will, for example with a small maxLength set. – sunadorer May 01 '12 at 09:58
  • I want to disable keyCode#66 is it possible? How can I do that? – Adil Malik Feb 05 '13 at 15:27
  • 1
    why keyCode==66 instead keyCode==EditorInfo.IME_ACTION_GO? – tse Dec 09 '15 at 11:22
8

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

Michael
  • 8,464
  • 2
  • 59
  • 62
Gibolt
  • 24,018
  • 9
  • 129
  • 89
5

This seems to work for me perfectly

int lineNum = 2;
mEditText.setHorizontallyScrolling(false);
mEditText.setLines(3);
yonez
  • 128
  • 2
  • 4
3

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;
         }
         }
    });
    
bcesars
  • 1,048
  • 1
  • 17
  • 36
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).

Community
  • 1
  • 1
Martin Stone
  • 11,637
  • 1
  • 35
  • 51
2

if you use the input option textImeMultiline with imeoptions flagnext and actionnext you get a next button instead of the cariage return

Marcusdev
  • 29
  • 1
2

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;
        }
});
Kaushik NP
  • 6,188
  • 8
  • 29
  • 57
2

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.

twall
  • 21
  • 4
1

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.

Community
  • 1
  • 1
Steve B
  • 1,146
  • 16
  • 16
0

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.
Gabriel Morin
  • 1,971
  • 1
  • 12
  • 22
0

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

Community
  • 1
  • 1
voytez
  • 1,636
  • 15
  • 13