Ответ 1
Я публикую это, потому что я не думаю, что любой из ответов действительно затрагивает вопрос. Снимок экрана в вопросе не соответствует определенному состоянию по умолчанию InputType. Таким образом, переключение InputTypes не даст вам макет из снимка экрана.
(на основе моих исследований...)
Поддержка ввода символов не регулируется каким-либо контрактом. Очень удобно оставить символы при создании своего собственного InputMethod
. ИЛИ, они могут добавить поддержку разбивки на страницы, чтобы обеспечить доступ к 100 символам. Может ли это быть связано контрактом? Может быть. Но это не в настоящее время.
Структура метода ввода не позволяет осуществлять прямую связь между клиентом и IME. Вся связь происходит либо через InputMethodManager
, либо через InputConnection
- односторонний канал. Однако переключение на символы с использованием ?123
является внутренним событием - не определенным состоянием/действием. Клиентские приложения не могут переключиться на него. Нет никакого публичного (или скрытого) API, чтобы это произошло.
InputType
указывает на нечто совершенно иное, чем IME. Не уверен, почему все рекомендуют его использование. Вы можете, конечно, найти, что конкретный InputType
предоставляет большинство необходимых ключей. Но это не то же самое, что show[ing] Android keyboard with symbols mode by default.
Возможное обходное решение:
Мы создадим пользовательский EditText
. Мы не должны. Он просто сохранит все в одном месте и спасет нас от кошмара с копией.
public class CusEditText extends EditText {
private final int mDefinedActionId;
public CusEditText(Context context, AttributeSet attrs) {
super(context, attrs);
// Corresponds to 'android:imeActionId' value
mDefinedActionId = getResources().getInteger(R.integer.definedActionId);
setOnEditorActionListener(new OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
Log.i("CusEditText", "onEditorAction, actionId = " + actionId);
// Only bother if (...)
if (actionId == mDefinedActionId) {
// Check if current InputType is NUMBER
if ((getInputType() & InputType.TYPE_CLASS_NUMBER) != 0) {
// Toggle
setImeActionLabel("NUM", mDefinedActionId);
setInputType(InputType.TYPE_CLASS_TEXT);
} else {
// Current InputType is TEXT // Toggle
setImeActionLabel("ABC", mDefinedActionId);
setInputType(InputType.TYPE_CLASS_NUMBER);
}
// We've handled this
return true;
}
// Let someone else worry about this
return false;
}
});
}
}
Далее, нам нужно определить definedActionId
. Откройте или создайте res/values/integers.xml
и добавьте:
<integer name="definedActionId">-100</integer>
-100
- произвольное значение. Я проверил EditorInfo
, и actionIds (IME_ACTION_XXXX
) были >= 0. -100
кажется хорошим кандидатом.
В xml ваш макет будет выглядеть так:
<com.your.packagename.CusEditText
android:layout_width="blah"
android:layout_height="blah"
android:inputType="number"
android:imeActionId="@integer/definedActionId"
android:imeActionLabel="ABC"/>
<!-- Probably use @string resource in place of ABC -->
Там нечего объяснять. IME запустится в режиме NUMBER. Вместо значка галочки он отобразит ABC
. При щелчке мы перехватываем actionId и переключаем между NUMBER и TEXT. Мы используем setInputType(...)
, потому что он не только обновляет InputType
, но также перезапускает IME с изменениями. setRawInputType(...)
обновляет только InputType
.
Вопросы
Как вы можете сказать, на самом деле это не решение. Если пользователь закрывает клавиатуру (используя кнопку back
) в режиме ТЕКСТ, клавиатура останется в режиме ТЕКСТ, когда они снова откроют ее. Чтобы перейти в режим NUMBER, пользователю нужно нажать NUM
. Кроме того, в режиме TEXT пользователь будет видеть NUM
как действие вместе с опцией ?123
. Это ничего не сломает, но отнимает у UX.
Мы ничего не можем сделать о ?123
в режиме ТЕКСТ по причинам, перечисленным выше. Но мы можем попытаться убедиться, что клавиатура всегда открывается в режиме NUMBER. Я расскажу о том, как мы это сделаем. Это не прямолинейно, так как мы (разработчики) не знакомы с такими событиями, как закрытие или открытие клавиатуры. Обновлено CusEditText
:
public class CusEditText extends EditText {
private final int mDefinedActionId;
private long mLastEditorActionTime = 0L;
public CusEditText(Context context, AttributeSet attrs) {
super(context, attrs);
// Corresponds to 'android:imeActionId' value
mDefinedActionId = getResources().getInteger(R.integer.definedActionId);
setOnEditorActionListener(new OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
Log.i("CusEditText", "onEditorAction, actionId = " + actionId);
// Only bother if (...)
if (actionId == mDefinedActionId) {
// setInputType(...) will restart the IME
// and call finishComposingText()
// see below
mLastEditorActionTime = SystemClock.elapsedRealtime();
// Check if current InputType is NUMBER
if ((getInputType() & InputType.TYPE_CLASS_NUMBER) != 0) {
// Toggle
setImeActionLabel("NUM", mDefinedActionId);
setInputType(InputType.TYPE_CLASS_TEXT);
} else {
// Current InputType is TEXT // Toggle
setImeActionLabel("ABC", mDefinedActionId);
setInputType(InputType.TYPE_CLASS_NUMBER);
}
// We've handled this
return true;
}
// Let someone else worry about this
return false;
}
});
}
@Override
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
InputConnection inputConnection = super.onCreateInputConnection(outAttrs);
return new CusInputConnectionWrapper(inputConnection, false);
}
private class CusInputConnectionWrapper extends InputConnectionWrapper {
private CusInputConnectionWrapper(InputConnection target, boolean mutable) {
super(target, mutable);
}
@Override
public boolean finishComposingText() {
Log.i("CICW", "finishComposingText");
// Ignore finishComposingText for 1 second (1000L)
if (SystemClock.elapsedRealtime() - mLastEditorActionTime > 1000L) {
if ((getInputType() & InputType.TYPE_CLASS_NUMBER) == 0) {
// InputConnection is no longer valid.
// Switch back to NUMBER iff required
setImeActionLabel("ABC", mDefinedActionId);
setInputType(InputType.TYPE_CLASS_NUMBER);
}
}
return super.finishComposingText();
}
}
}
Опять же, код не требует пояснений. Мы создаем InputConnectionWrapper
и слушаем обратный вызов finishComposingText()
. Если мы переключаемся вручную между TEXT
и NUMBER
, мы используем флаг, так как finishComposingText()
будет вызываться автоматически. В противном случае мы проверяем, установлен ли тип ввода на TEXT
и измените его на NUMBER
. Я не уверен, что finishComposingText()
является правильным методом для интерпретации закрытия/открытия клавиатуры. Тестирование по API 21, vanilla android, похоже, работает. Дополнительные тесты потребуются.
Я действительно надеюсь, что кто-то может придумать лучшее, более надежное решение, чем это, или изменить мое обходное решение, чтобы оно не выглядело как.
Резюме
Задача состоит в том, чтобы обеспечить функциональность переключения между режимами ввода NUMBER и TEXT вокруг существующих двигателей входных методов (IME). Первый подход заключался в использовании imeActionLabel & imeActionId
в механизме переключения. Этот подход хорошо работал с клавиатурой Google (это imeActionLabel), но не удалось с Samsung - imeActionLabel
не отображается в портрете (без extract). Возможным обходным путем является включение кнопки переключения в собственный пользовательский интерфейс приложения.
Даже с клавиатурой Google буквы (текст) не отображаются, когда режим переключается на NUMBER после ввода букв. Эта проблема была исправлена (по крайней мере, на тестируемых устройствах), используя флаг flagNoExtractUi
, который не позволяет IME войти в полноэкранный режим в альбомной ориентации.
Окончательное решение (ожидает выполнения и тестирования)
- IME запускается в режиме ввода NUMBER (95% случаев использования включают ввод номера)
- Кнопка добавления в пользовательский интерфейс приложения (рядом с
EditText
) для переключения между режимами NUMBER и TEXT - Пользователь может переключаться с NUMBER на TEXT без каких-либо ограничений. Переход от TEXT к NUMBER требует, чтобы никакие алфавиты не были добавлены.
- Тип ввода сохраняется между закрытием клавиатуры и повторным открытием. Пример. Если пользователь переключится в режим ТЕКСТ и закроет клавиатуру, он откроется в режиме ТЕКСТ. Тип InputType не reset.
Для получения дополнительной информации о проверенных подходах обратитесь к этой теме обсуждения.
Скриншоты
По умолчанию (NUMBER):
Переключено в TEXT: