Как я могу использовать пользовательский шрифт во входной области метода ввода?

Мы разрабатываем приложение, в котором нам нужно использовать специальный шрифт ( Typeface загруженный из активов приложения) в EditText . В методе ввода Android docs указано следующее:

Когда фокус ввода перемещается в редактируемое текстовое поле или выходит из него, Android показывает или скрывает метод ввода (например, экранную клавиатуру), если это необходимо. Система также принимает решения о том, как ваш пользовательский интерфейс и текстовое поле появляются над методом ввода. Например, когда вертикальное пространство на экране ограничено, текстовое поле может заполнить все пространство над методом ввода.

Это смелая часть, которая нас сбивает с толку. Фраза «текстовое поле может быть заполнена …» представляется вводящей в заблуждение, поскольку текстовое поле, которое используется, не является EditText который мы настроили с помощью нашего пользовательского шрифта. ( ПРИМЕЧАНИЕ: ответы до сих пор объясняют, как установить пользовательский шрифт в EditText . Мы уже настраиваем пользовательский шрифт в EditText . Пожалуйста, внимательно прочитайте вопрос перед ответом.) Вот скриншот с скрытым методом ввода:

Диалог

Вот что происходит, когда отображается мягкая клавиатура, а вертикальное пространство ограничено:

Ограниченное вертикальное пространство

Как вы можете видеть, шрифт в текстовом поле над методом ввода не является нашим пользовательским шрифтом (я предполагаю, что это шрифт Roboto по умолчанию). Это происходит для каждой мягкой клавиатуры, которую мы пробовали в качестве метода ввода.

Я хочу подчеркнуть, что когда пространство ограничено, этот вид над клавиатурой генерируется внутри системы, а не каким-либо из нашего кода.

Главный вопрос: есть ли способ (и, если да, что это такое?), Чтобы контролировать появление этого (из-за отсутствия лучшей терминологии) прокси-представления – как минимум, чтобы заставить его использовать наш пользовательский шрифт?

Это было бы дополнительным преимуществом, если бы мы могли также контролировать макет и внешний вид всей области прокси над клавиатурой (включая кнопку «Готово»). Мы используем вариацию методики, описанной в этом потоке, чтобы наша деятельность использовала локаль, отличную от той, которая установлена ​​в системе, но локаль действия явно не применяется здесь. (Если бы это было так, кнопка была бы слева и читала бы «בוצע», как это происходит, если я изменю локаль устройства на иврит. [EDIT: Я могу получить правильную метку кнопки, используя атрибут android:imeActionLabel на EditText . Однако я не знаю, как контролировать направленность макета.])

EDIT По запросу, вот как я создаю свой диалог (соответствующие части, взятые из DialogFragment ):

 public Dialog onCreateDialog(Bundle savedInstanceState) { final Dialog dlg = new Dialog(getActivity(), android.R.style.Theme_Holo_Light_Dialog_NoActionBar); dlg.setContentView(R.layout.edit_note_dialog); mAnimator = (ViewAnimator) dlg.findViewById(R.id.animator); final Typeface hebrew = SystemData.getHebrewFont(); mNoteEditor = (EditText) dlg.findViewById(R.id.note_field); mNoteEditor.setTypeface(hebrew); // etc. (setting fonts for other elements, adding listeners, etc.) } 

И вот макет:

 <?xml version="1.0" encoding="utf-8"?> <ViewAnimator xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/animator" android:layout_width="match_parent" android:layout_height="match_parent" > <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_horizontal" android:paddingTop="10dp" android:text="@string/loading" /> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" > <TextView android:id="@+id/title" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:background="@android:color/black" android:gravity="center" android:text="@string/edit_note_title" android:textColor="@android:color/white" android:textSize="20sp" /> <TextView android:id="@+id/citation" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@+id/title" android:layout_centerHorizontal="true" android:background="@android:color/black" android:gravity="center" android:textColor="@android:color/white" android:textSize="16sp" /> <LinearLayout android:id="@+id/actions" style="?android:attr/buttonBarStyle" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:layout_margin="5dp" > <Button android:id="@+id/cancel" style="?android:attr/buttonBarButtonStyle" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="8dp" android:gravity="center" android:minWidth="32dp" android:text="@string/cancel" android:textSize="@dimen/nav_interior_item_size" /> <Button android:id="@+id/close" style="?android:attr/buttonBarButtonStyle" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginEnd="8dp" android:gravity="center" android:minWidth="32dp" android:text="@string/save" android:textSize="@dimen/nav_interior_item_size" /> </LinearLayout> <Button android:id="@+id/undo" style="?android:attr/buttonBarButtonStyle" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_alignParentStart="true" android:layout_margin="5dp" android:text="@string/edit_note_undo" android:textSize="@dimen/nav_interior_item_size" /> <Button android:id="@+id/redo" style="?android:attr/buttonBarButtonStyle" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_alignParentEnd="true" android:layout_margin="5dp" android:text="@string/edit_note_redo" android:textSize="@dimen/nav_interior_item_size" /> <EditText android:id="@+id/note_field" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_above="@+id/actions" android:layout_below="@+id/citation" android:focusableInTouchMode="true" android:gravity="top" android:hint="@string/edit_note_hint" android:imeActionLabel="@string/done" android:inputType="textMultiLine|textNoSuggestions" android:lineSpacingMultiplier="1.2" /> </RelativeLayout> </ViewAnimator> 

Solutions Collecting From Web of "Как я могу использовать пользовательский шрифт во входной области метода ввода?"

Было бы просто, если бы у вас был экземпляр InputMethodService. Существует способ установить тему или даже установить извлеченное представление .

Проблема в том, что вам нужно создать пользовательскую реализацию метода ввода, и пользователям придется выбирать его в системных настройках.

Обновить:

Вы можете попробовать:

    • android:windowSoftInputMode="adjustResize"
    • Сделать просмотр прокручиваемым

или

    • Используйте IME_FLAG_NO_EXTRACT_UI
    • Установите OnEditorActionListener на EditText чтобы на клавиатуре появилась кнопка действия.
    • Создавать пользовательские макеты или скрывать / показывать элементы, когда высота экрана слишком мала. Например, скрыть кнопки внизу и показать кнопки с правой стороны. Он может быть похож на представление экстракта по умолчанию.

Приемник макета для диалога или EditText:

  mViewContainer.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { //unregister the layout listener if needed. int heightPixels = mViewContainer.getHeight(); Resources resources = mContext.getResources(); int heightDip = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, heightPixels, resources.getDisplayMetrics()); if (heightDip < MIN_HEIGHT) { mBottomButtons.setVisibility(View.GONE); mSideButtons.setVisibility(View.VISIBLE); } else { mBottomButtons.setVisibility(View.VISIBLE); mSideButtons.setVisibility(View.GONE); } } }); 

Изменение видимости на GONE запросит ретрансляцию, и слушатель снова запустится, что может привести к циклу.

Единственный способ, который я вижу, – отключить полноэкранный режим редактирования для вашего EditText, который автоматически срабатывает, когда ваш EditText недостаточно высок.

 mNoteEditor.setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI); 

Вы можете исправить проблемы изменения размера диалогового окна с помощью

 dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); 

Возможно, ваш диалог должен быть заключен в ScrollView .

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

Остерегайтесь, взломанные и непроверенные решения:

Копаясь в исходном коде Android, я обнаружил, что каждый IME содержит реализацию AbstractInputMethodService . Android предоставляет стандартную реализацию ( android.inputmethodservice.InputMethodService ), которая, если вы посмотрите, имеет открытый метод setExtractView и метод onCreateExtractTextView , который раздувает com.android.internal.R.layout.input_method_extract_view.xml , который, в свою очередь, содержит com.android.internal.R.id.inputExtractEditText ! Таким образом, хакерское решение будет состоять в том, чтобы надеяться, что в базе данных InputMethodServices от IME вашего клиента используется тот же XML (что, насколько я могу судить, было в Android некоторое время), и вы можете попытаться получить ссылку на этот EditText на Это идентификатор и изменить шрифт. К сожалению, я не уверен, что в иерархии / окне представления добавлены представления InputMethodService, и если они доступны из процесса вашего приложения / активности.

Источник для InputMethodService: https://github.com/android/platform_frameworks_base/blob/master/core/java/android/inputmethodservice/InputMethodService.java

Источник для компоновки XML: https://github.com/android/platform_frameworks_base/blob/master/core/res/res/layout/input_method_extract_view.xml

Если вы действительно хотите попасть в беду, возможно, есть способ получить ссылку на сервис IME и использовать отражение, чтобы изменить извлеченное представление. Стандартный InputMethodService содержит частную ссылку на mExtractEditText

Я не знаю ответа, которого вы ищете, но, возможно, он поместит вас в правильном направлении … или, по крайней мере, в каком-то направлении.

Если у вас есть один редактируемый элемент в диалоге, как насчет обработки изменений ориентации и

  • В случае портретной ориентации, покажите диалог
  • В случае ландшафтной ориентации, покажите полноэкранный фрагмент с помощью EditText и Buttons (как указывали другие, отключите полноэкранный режим редактирования для EditText), запросите фокус для EditText, show Keyboard.
  • В случае переключения ориентации отмените диалог / показать фрагмент с уже введенным текстом (и наоборот)

Это может быть концептуально хорошо, потому что, если пользователь хочет ввести текст, он / она всегда будет в полноэкранном режиме редактирования в альбомной ориентации. И поскольку в исходном диалоге есть только один редактируемый вид, вам явно не нужен диалог, чтобы выбрать что-нибудь еще для редактирования (например, другой EditText).