Android IME,在EditText中设置光标位置

时间:2013-11-27 10:12:58

标签: android android-edittext android-softkeyboard

我正在使用软键盘,我需要在IME编辑文本中设置光标位置。

enter image description here

如上图所示,我创建了软键盘,因为我们可以看到在编辑文本和当前光标位置输入了一些文本(由蓝色指示符显示)。

我需要将光标位置设置在当前行的末尾(在我们的情况下,首先在图像中以红色显示的行的末尾)

我尝试使用[{1}}提供的不同功能,我尝试过,

InputConnection

还有一件事,我还需要计算编辑文本中的行数(在我们的例子中是两行)。

4 个答案:

答案 0 :(得分:3)

其他一些答案似乎过于复杂或不完整。这是未来访客的一般答案。

在活动中

如果您对EditText有引用,那么很容易。

设置光标位置

editText.setSelection(index);

设置所选范围

editText.setSelection(startIndex, endIndex);

在IME(键盘)

因为您无法直接访问EditText,因此从IME中获得更多困难。但是,您可以使用InputConnection设置光标位置和选择。

以下答案从InputMethodService子类中获取这样的输入连接:

InputConnection inputConnection = getCurrentInputConnection();

设置光标位置

inputConnection.setSelection(index, index);

设置所选范围

inputConnection.setSelection(startIndex, endIndex);

将光标移至开始

inputConnection.setSelection(0, 0);

将光标移至末尾

ExtractedText extractedText = inputConnection.getExtractedText(new ExtractedTextRequest(), 0);
if (extractedText == null || extractedText.text == null) return;
int index = extractedText.text.length();
inputConnection.setSelection(index, index);

这种方法不能保证工作,因为如果文本很长,提取的文本将不是EditText中的整个文本。但是,对于大多数情况来说,这很好。另一种选择是使用以下

的组合
  • inputConnection.getTextBeforeCursor(numberOfChars, 0)
  • inputConnection.getSelectedText(0)
  • inputConnection.getTextAfterCursor(numberOfChars, 0)

其中numberOfChars是一个很大的数字。

获取当前光标索引(或选择)

ExtractedText extractedText = inputConnection.getExtractedText(new ExtractedTextRequest(), 0);
int startIndex = extractedText.startOffset + extractedText.selectionStart;
int endIndex = extractedText.startOffset +  extractedText.selectionEnd;

如果extractedText未返回EditText的全文,则startOffset会告诉您它从何处被拉出。然后,您可以通过将startOffset添加到提取的文本的选择开始或结束来获取实际的光标索引。

相对于当前位置移动光标

一旦知道光标的当前位置,就可以轻松移动光标。下面是一个将光标移动到上一个单词开头的示例。

BreakIterator boundary = BreakIterator.getWordInstance();
boundary.setText(extractedText.text.toString());
int preceding = boundary.preceding(extractedText.selectionStart);
int newIndex = (preceding == BreakIterator.DONE) ? selectionStart : preceding;
inputConnection.setSelection(newIndex, newIndex);

请参阅其他BreakIterator个选项here

您还可以通过向下发送d-pad事件向左,向右,向上和向下移动。

向左移动

inputConnection.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_LEFT));
inputConnection.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_LEFT));

向右移动

inputConnection.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_RIGHT));
inputConnection.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_RIGHT));

向上移动

inputConnection.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_UP));
inputConnection.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_UP));

向下移动

inputConnection.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_DOWN));
inputConnection.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_DOWN));

答案 1 :(得分:2)

  

嗨,各位朋友,谢谢。在两天之前我得到了我的   解决方案,但无法更新我的答案。

     

为此,我使用了下面的代码,

     

如果我们使用的api版本大于10,

sendDownUpKeyEvents(0x0000007b);
  

因为这个方法是在api 11中添加的。

     

如果我们使用的api版本低于11,

if (getCurrentInputConnection() != null) {
                    CharSequence textAfter = getCurrentInputConnection().getTextAfterCursor(1024, 0);
                    if (!TextUtils.isEmpty(textAfter)) {
                        int newPosition = 1;
                        while (newPosition < textAfter.length()) {
                            char chatAt = textAfter.charAt(newPosition);
                            if (chatAt == '\n' || chatAt == '\r') {
                                break;
                            }
                            newPosition++;
                        }
                        if (newPosition > textAfter.length())
                            newPosition = textAfter.length();
                        try {
                            CharSequence textBefore = getCurrentInputConnection().getTextBeforeCursor(Integer.MAX_VALUE, 0);
                            if (!TextUtils.isEmpty(textBefore)) {
                                newPosition = newPosition + textBefore.length();
                            }
                            getCurrentInputConnection().setSelection(newPosition, newPosition);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }

答案 2 :(得分:1)

下面是一些可以做你想要的工作代码。

这很简单:

要将光标位置设置为第一行的末尾,我们首先必须获取该行的最后一个文本字符的索引。 EditTexts的布局上有一种方法可以执行此操作。

布局是edittext在内部用于布局文本的内容,它有一个名为 getLineEnd 的方法,它返回一行末尾的文本索引(我们需要从中减去1,否则我们的光标会在下一行的开头结束。)

一旦我们有了设置光标的位置,我们只需使用EditText的 setSelection 方法。

int endOfFirstLine = editText.getLayout().getLineEnd(0)-1;
//set the text selection (cursor postion) to that index
editText.setSelection(endOfFirstLine);

我们也可以通过

轻松获得行数
int lineCount = editText.getLineCount();

使用此代码的技巧是,必须在构建EditText的布局后运行它。这意味着如果我们将它放在onCreate或onResume上,它就行不通。行数为0.

因此我们必须在布局传递完成后运行此代码。我们通过向edittext添加布局侦听器,并在完成后运行代码来完成此操作。

editText.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
            @Override public void onGlobalLayout() {
}

以下是完整的活动代码:

public class MainActivity extends Activity {

    private EditText editText;

    @Override protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        editText = (EditText) findViewById(R.id.test_edittext);

        editText.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
            @Override public void onGlobalLayout() {

                //this gives us the index of the text at the end of the first line.
                int endOfFirstLine = editText.getLayout().getLineEnd(0)-1;
                //set the text selection (cursor postion) to that index
                editText.setSelection(endOfFirstLine);

                //we can get the line count with getLineCount
                int lineCount = editText.getLineCount();

                Toast.makeText(MainActivity.this, "number of edittext lines: " + lineCount, Toast.LENGTH_LONG).show();
            }
        });

    }

    @Override protected void onResume() {
        super.onResume();



    }

}

答案 3 :(得分:1)

我很遗憾地说你无法通过IME做到这一点。为此,您应该访问EditText的某些方法,但是没有任何可用的API可用,因为textview控件在活动中是另一个进程,而不是您的进程。

您可以获得的所有信息都是您在EditorInfo参数中可以看到的,您可以在一些InputMethodService方法中看到这些信息,例如onStartInput(EditorInfo属性,布尔重启)。可能在未来还包括一些其他方式来访问更多信息,但此时,你可以做的就是你要求的一切,就是用setSelection InputConnection方法更改光标位置,但你也不知道第一行末尾的位置是哪一个,所以对你所需的东西不是很有用。