带完成操作按钮的多行 EditText

有没有可能有一个 EditText小部件与 android:inputType="textMultiLine"集,和 android:imeOptions="actionDone"在同一时间?

我想要一个多行编辑框,与键盘上的行动按钮完成,而不是回车(回车) ,但它似乎不工作。

75858 次浏览

如果与屏幕上键盘的外观无关,那么您可以简单地在键盘上放置一个输入侦听器,并在用户输入换行符时触发“ done”状态。

简短的回答: 不,我相信在 API 级别11(3.0)之前是不可能的。

这里也出现了同样的问题(在对已接受答案的评论中讨论过) :

Android 软键盘操作按钮

来自最后的评论:

看看我手机上的一些应用程序,最后一个是多行框,下面有一个可见的“完成”或“发送”按钮(例如电子邮件应用程序)。

我觉得这才是你该做的。有了 android:inputType="textMultiLine"android:imeOptions="actionDone"使输入键的功能变得模棱两可。请记住,您可以使用 android:lines="10",也许删除 android:inputType="textMultiLine",但取决于您想要达到的目标,有时您只需要 android:inputType="textMultiLine",没有替代品。

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;
}
});

来自 android 文档:’< em > “ textMultiLine” 普通文本键盘,允许用户输入包含 换行(回车)的长文本字符串。因此,如果你想在键盘上有“完成”按钮,textMultiLine 属性是不合适的。译注:

使用 done 按钮获得多行(在本例中为3行)输入字段的一个简单方法是使用 EditText

android:lines="3"
android:scrollHorizontally="false"

但是,出于某种原因,这只适用于我,如果我在代码中做这些设置,而不是布局文件(在 onCreate)

TextView tv = (TextView)findViewById(R.id.editText);
if (tv != null) {
tv.setHorizontallyScrolling(false);
tv.setLines(3);
}

我希望这能帮到别人,因为我花了很长时间才弄明白。如果你能从载货清单上找到解决办法,请告诉我们。

如果您使用输入选项 textImeMultiline 和 imeoptions Flag next 以及 actionnext,您将得到一个 next 按钮,而不是 cariage 返回

我在4.x 上尝试调用 setHorizontallyScroll ()(有或没有 setLine ()或 setMaxLines ()) ,以及许多不同的 XML 配置,以显示“完成”按钮。都没用。底线是,如果您的 EditText 是多行的,Android 将总是希望显示回车,而不是“完成”按钮,除非您在这方面进行了一些修改。

我发现的不涉及重新映射回车行为的最简单的解决方案在这里: https://stackoverflow.com/a/12570003/3268329。这个解决方案将消除 Android 强制设置多行视图的 IME _ FLAG _ NO _ ENTER _ ACTION 标志的无情愿望,这将导致“完成”按钮消失。

解决这种情况的一个简单方法是:

  • 将这些属性保存在 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;
    }
    }
    });
    

工作范例! 创建以下支持此特性的自定义 EditText 类,并在 xml 文件中使用该类:

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" />

我也挣扎了很长一段时间,但我终于找到了一个解决办法!

像这样创建一个自定义 EditText 类:

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();
}
}

这个类移除 lineBreaks (n) ,像 textMultiline 那样包装文本,AND 允许您用 ImeAction 替换 Enter 按钮;)。

您只需要在 XML 中调用它,而不是经典的 EditText 类。

为了解释这里的逻辑:

  • 将 EditText 设置为 singleLine,以便能够显示 ImeAction 按钮而不是 Enter。
  • 移除水平滚动,使文本在到达视图末尾时转到下一行。
  • 使用 onGlobalLayoutListener 观察布局变化,并将其“ line”参数设置为 EdText 保存的当前文本的“ lineCount”。这是刷新它高度的东西。

工作解决方案在这里,创建您的自定义 EditTextView (只是扩展文本视图) ,并用一段代码覆盖 onInputConnection,您可以在这里找到公认的答案: 2.3版带有完成软输入操作标签的多行 EditText

使用

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

以及 XML 格式:

android:inputType="textMultiLine"

虽然没有其他的解决方案曾经为我工作,下面的 成功了漂亮,节省了我的日子更多的谷歌天天,与我自己的一些曲折当然。不幸的是,我不记得我到底从哪里得到的代码,所以不能给作者他/她应得的信任。

在 Java 代码中:

////////////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;
}
});

这看起来对我很有效

int lineNum = 2;
mEditText.setHorizontallyScrolling(false);
mEditText.setLines(3);

为了在 Kotlin 实现这一点(也可以选择应用其他配置,比如 textCapSentences,你可以使用这个扩展函数:

// 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)
}

用法:

myEditText.setMultiLineCapSentencesAndDoneAction()

可重复使用的 Kotlin 溶液

设置这些值 代码 是唯一对我有效的方法

edittext.inputType = EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE
edittext.setHorizontallyScrolling(false)
edittext.maxLines = Integer.MAX_VALUE // Or your preferred fixed value

我经常需要这样做,所以这样做是为了保持代码的整洁:

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)

如果你想在“完成”上添加一个可选的自定义操作,试试这个:

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()

需要在回调中轻松控制键盘吗

然后在 EditText.multilineDone中添加 hideKeyboard()调用

如果使用 DataBinding,则应创建一个将捕获操作的方法。

一些带有扩展方法的文件,例如 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()
}

然后在 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}" />

编写 UI的代码是:

TextField(
...
keyboardOptions = KeyboardOptions(
imeAction = ImeAction.Done
),
...
)