如何在输入法的输入区域中使用自定义字体?

时间:2014-09-10 03:51:17

标签: android android-edittext android-softkeyboard android-input-method

我们正在开发一款应用,我们需要在Typeface中使用自定义字体(从应用资源中加载EditText)。 Android input method docs表示以下内容:

  

当输入焦点移入或移出可编辑文本字段时,Android会根据需要显示或隐藏输入法(例如屏幕键盘)。系统还会决定UI和文本字段在输入方法上方的显示方式。例如,当屏幕上的垂直空间受到约束时,文本字段可能会填充输入法上方的所有空格。

大胆的部分正在绊倒我们。短语“文本字段可能会填充......”似乎具有误导性,因为使用的文本字段不是我们使用自定义字体设置的EditText。 (注意:到目前为止,所有答案都解释了如何在EditText中设置自定义字体。我们已经在EditText中设置了自定义字体。请在回答之前仔细阅读问题。)这是隐藏输入法的屏幕截图:

the dialog

以下是软键盘显示和垂直空间受限时会发生的情况:

constrained vertical space

正如您所看到的,输入法上方文本字段中的字体不是我们的自定义字体(我猜它是系统的默认Roboto字体)。对于我们尝试作为输入法的每个软键盘都会发生这种情况。

我想强调的是,当空间受限制时,键盘上方的这个视图是由系统内部生成的,而不是我们的任何代码生成的。

主要问题是:是否有办法(如果是这样,它是什么?)来控制它的外观(缺乏更好的术语)代理视图 - 至少让它使用我们的自定义字体?

如果我们还可以控制键盘上方整个代理区域的布局和外观(包括“完成”按钮),这将是一个额外的好处。我们使用this thread中描述的技术的变体来使我们的活动使用与系统中设置的区域不同的区域设置,但是活动的区域设置显然没有在这里应用。 (如果是的话,按钮将在左侧,并且会显示“בוצע”,如果我将设备的区域设置更改为希伯来语,就会发生这种情况。[编辑:我可以使用android:imeActionLabel属性获取正确的按钮标签在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 个答案:

答案 0 :(得分:4)

如果您有一个InputMethodService实例,那将很简单。 有一种方法可以设置theme甚至set extracted view

问题是你必须创建Input Method的自定义实现,用户必须在系统设置中选择它。

更新

您可以尝试:

    • android:windowSoftInputMode="adjustResize"
    • 使视图可滚动
      • 使用IME_FLAG_NO_EXTRACT_UI
      • OnEditorActionListener上设置EditText以在键盘上设置操作按钮。
      • 在屏幕高度太小时创建自定义布局或隐藏/显示元素。例如,底部隐藏按钮,右侧显示按钮。它看起来与默认的提取视图类似。
    1. 对话框或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将请求重新布局,并且侦听器将再次运行可能导致循环的内容。

答案 1 :(得分:3)

我能看到的唯一方法是disable the fullscreen editing mode for your EditText当EditText不够高时自动启动。

mNoteEditor.setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI);

您可以使用

修复调整对话框大小调整问题的对话框
dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);

您的对话框布局可能应该包含在ScrollView

答案 2 :(得分:2)

我认为正如其他人所说的那样,不幸的是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包含{ {1}}!所以一个hacky解决方案是希望你的大多数客户的IME的InputMethodServices使用相同的XML(据我所知,已经在Android中使用了一段时间),你可以尝试通过以下方式获取对此EditText的引用它的ID并改变它的字体。不幸的是,我不确定是否在视图层次结构/窗口中添加了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的包私有引用:)

我不知道你正在寻找的答案,但也许它会让你朝着正确的方向......或者至少是某个方向。

答案 3 :(得分:2)

如果您的对话框上有单个可编辑元素,那么如何处理方向更改和

  • 如果是纵向,请显示对话框
  • 如果是横向,请使用EditText和Buttons显示全屏片段(正如其他人所说;禁用EditText的全屏编辑模式),请求焦点为EditText,显示键盘。
  • 在方向切换的情况下解除Dialog / show Fragment与已输入的文本(反之亦然)

这可能在概念上很好,因为如果用户希望输入文本,他/她将始终以横向方向结束全屏编辑布局。由于原始对话框中只有只有一个可编辑视图,您并不明确需要使用对话框来选择其他任何内容进行编辑(例如,另一个EditText)。