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

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

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

это часть жирным шрифтом, что спотыкается нас. Фраза "текстовое поле может заполнить..." кажется, вводит в заблуждение, что текстовое поле, которое используется, не является EditText что мы настроили с нашим пользовательским шрифтом. (Примечание: ответы до сих пор все объясняют, как установить пользовательский шрифт в элементе EditText. мы уже устанавливаем пользовательский шрифт в EditText. пожалуйста, внимательно прочитайте вопрос, прежде чем ответить.) Вот скриншот со скрытым методом ввода:

the dialog

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

constrained vertical space

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

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

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

это будет дополнительный бонус, если мы также можно управлять компоновкой и внешним видом всей прокси-области над клавиатурой (включая кнопку "Готово"). Мы используем вариацию метода, описанного в этой теме чтобы наша активность использовала локаль, отличную от установленной в системе, но локаль активности явно не применяется здесь. (Если бы это было так, кнопка была бы слева и читала "וו.", как это происходит, если я изменяю языковой стандарт устройства на иврит. [EDIT: я могу получить правильный метка кнопки с помощью на EditText. Однако, я не знаю, как контролировать направленность макета.])

редактировать в запросе, вот как я строю свой диалог (соответствующие части, извлеченные из 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>

4 ответов


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

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

обновление:

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

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

или

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

прослушиватель макета для диалога или 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.

остерегайтесь, hacky и непроверенное решение входящих:

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

источник 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 и кнопки (как другие заявили; отключить полноэкранный режим редактирования для EditText), фокус запроса для EditText, показать клавиатуру.
  • в случае переключения ориентации закрыть диалог / показать Фрагмент с уже введенным текстом (и наоборот)

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