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

我们正在开发一个应用程序,我们需要在EditText使用自定义字体(从应用程序资产加载的Typeface )。 Android输入法docs说明如下:

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

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

对话框

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

约束垂直空间

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

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

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

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

这是布局:

        

如果您有一个InputMethodService实例,那将很简单。 有一种方法可以设置主题甚至设置提取的视图 。

问题是您必须创建输入法的自定义实现,用户必须在系统设置中选择它。

更新:

您可以尝试:

    • android:windowSoftInputMode="adjustResize"
    • 使视图可滚动

要么

    • 使用IME_FLAG_NO_EXTRACT_UI
    • EditText上设置OnEditorActionListener以在键盘上有一个操作按钮。
    • 当屏幕高度太小时,创建自定义布局或隐藏/显示元素。 例如,底部隐藏按钮,右侧显示按钮。 它看起来类似于默认的提取视图。

对话框或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 ),如果你看一下,它有一个公共的setExtractView方法,以及一个onCreateExtractTextView方法,它会使com.android.internal.R.layout.input_method_extract_view.xml膨胀,后者又包含com.android.internal.R.id.inputExtractEditText ! 所以一个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服务本身的引用,并使用reflection来改变提取的视图。 标准的InputMethodService包含对mExtractEditText的包私有引用:)

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

如果Dialog上有一个可编辑的元素,那么处理方向的变化和

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

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