Android IME, установить позицию курсора в EditText

Я работаю на мягкой клавиатуре, где мне нужно установить положение курсора в тексте редактирования IME.

enter image description here

как показано на рисунке выше, я создал мягкую клавиатуру, так как мы видим, что текст вводится в текст редактирования и текущую позицию курсора(отображается синим индикатором).

мне нужно установить положение курсора в конце текущей строки (в нашем случае в конце строки, впервые показанной красным цветом на изображении)

Я пробовал с разных функции с InputConnection, Я пробовал,

CharSequence seq = conn.getTextBeforeCursor(1000, 0);     // will get as much characters as possible on the left of cursor

и еще одна вещь, мне нужно подсчитать количество строк в редактирование текста (в нашем случае это два).

4 ответов


Ниже приведен некоторый рабочий код, чтобы сделать то, что вы хотите.

Это довольно просто:

установить курсор в конец первой строки, мы сначала должны получить индекс последнего символа текста в этой строке. Существует метод на EditTexts'планировка для этого.

на планировка - это то, что edittext использует внутренне для компоновки текста, и у него есть метод getLineEnd, которая возвращает текстовый индекс в конце строки (Нам нужно вычесть 1 из этого, иначе наш курсор закончится в начале следующей строки).

как только у нас есть позиция для установки курсора, мы просто используем помощью методов setselection метод EditText.

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



    }

}

привет друзья спасибо за признательность. Перед два дня я получил мое решение, но не может обновить мой ответ.

для этого я использовал ниже код,

Если мы используем версию 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();
                        }
                    }
                }

мне жаль говорить, что вы не сможете сделать это из IME. Для этой цели вы должны получить доступ к некоторым методам EditText, но нет никакого возможного API, потому что элемент управления textview находится в действии другого процесса, а не вашего процесса.

вся информация, которую вы можете получить, - это то, что у вас есть в параметре EditorInfo, который вы можете увидеть в некоторых методах InputMethodService, таких как onStartInput(атрибут EditorInfo, логический перезапуск). Вероятно, в будущее включает в себя какой-то другой способ доступа к дополнительной информации, но на данный момент все, что вы можете сделать os, что вы просите, это изменить положение курсора с помощью setSelection метод InputConnection, но вы также не знаете, какая позиция конца первой строки, так что это не будет действительно полезно для того, что вам нужно.


некоторые из других ответов кажутся слишком сложными или неполными. Это общий ответ для будущих посетителей.

в деятельности

если у вас есть ссылка на EditText, то это легко.

установите положение курсора

editText.setSelection(index);

установить выбранный диапазон

editText.setSelection(startIndex, endIndex);

в IME (клавиатура)

это немного сложнее изнутри IME, потому что у вас нет прямой доступ к EditText. Однако вы можете использовать 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, the 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 опции здесь.

вы также можете двигаться влево, вправо, вверх и вниз, отправив 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));