我创建了一个自定义键盘,效果很好 - 除了前两行键的预览视图显示得不够高。它们的垂直位置受到父布局的约束。
这些屏幕截图说明了问题 - 预览的位置' 0'和' 8'很好,但对于' 5'和' 2'它不是:
键' 0'的预览显示在按钮上方......
键' 8'的预览也显示在按钮上方......
但关键' 5'的预览没有显示在按钮上方......
关键' 2'的预览没有显示在按钮上方......
如何克服,所以预览' 5'和' 2'显示在它们各自的键上方相同的距离,就像它用于' 0' 0和' 8'。
这是我的 keyboard.xml ...
<android.inputmethodservice.KeyboardView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/keyboard"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:keyPreviewLayout="@layout/keyboard_key_preview" />
这是我的 keyboard_key_preview.xml ...
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:background="@color/keyboard_preview_bg"
android:textColor="@color/keyboard_preview_fg"
android:textStyle="bold"
android:textSize="@dimen/keyboard_preview_text_size" />
这是我的 keyboard_numeric.xml 布局......
<Keyboard
xmlns:android="http://schemas.android.com/apk/res/android"
android:keyWidth="33.33%p"
android:keyHeight="@dimen/keyboard_key_height"
android:horizontalGap="@dimen/keyboard_horizontal_gap"
android:verticalGap="@dimen/keyboard_vertical_gap">
<Row android:rowEdgeFlags="top">
<Key android:codes="49" android:keyLabel="1" android:keyEdgeFlags="left"/>
<Key android:codes="50" android:keyLabel="2"/>
<Key android:codes="51" android:keyLabel="3" android:keyEdgeFlags="right"/>
</Row>
<Row>
<Key android:codes="52" android:keyLabel="4" android:keyEdgeFlags="left"/>
<Key android:codes="53" android:keyLabel="5"/>
<Key android:codes="54" android:keyLabel="6" android:keyEdgeFlags="right"/>
</Row>
<Row>
<Key android:codes="55" android:keyLabel="7" android:keyEdgeFlags="left"/>
<Key android:codes="56" android:keyLabel="8"/>
<Key android:codes="57" android:keyLabel="9" android:keyEdgeFlags="right"/>
</Row>
<Row android:rowEdgeFlags="bottom">
<Key android:codes="-5" android:keyIcon="@drawable/ic_backspace_white_24dp" android:isRepeatable="true" android:keyEdgeFlags="left" />
<Key android:codes="48" android:keyLabel="0"/>
<Key android:codes="-4" android:keyLabel="DONE" android:keyEdgeFlags="right"/>
</Row>
</Keyboard>
答案 0 :(得分:7)
预览键实际上是在PopupWindow
的构造函数中创建的KeyboardView
。 (参见代码here)。
您看到的问题是因为PopupWindow
被其父级裁剪。如果可以为PopupWindow
禁用剪裁,则预览键将能够弹出&#34;弹出&#34;在键盘视图之外。如果在上面引用的代码中设置断点并执行以下代码,则可以看到此方法有效:
mPreviewPopup.setClippingEnabled(false)
请参阅PopupWindow
文档中的setClippingEnabled。默认情况下,启用剪裁。
setClippingEnabled
void setClippingEnabled(boolean enabled)
允许弹出窗口超出屏幕范围。默认情况下,窗口被剪切到屏幕边界。将此设置为false将允许窗口准确定位。
它说&#34;屏幕,&#34;但它也适用于键盘窗口。
剩下的问题是:如何禁用剪裁?不幸的是,mPreviewPopup
是一个私有变量。反思将提供访问但不理想。我还没有找到另一种方法来禁用此私有PopupWindow
的剪辑,所以这只是指向分辨率而不是分辨率本身。
更新:我又看了一下发生了什么。以下是我在各种API级别中发现的内容。
API 17-21:允许键盘预览弹出键盘边界。
API 22,23,25-26:键预览受限于键盘的边界,但确实完整显示。这就是OP所看到的。
API 24:键预览被约束到键盘的边界,但是被剪裁。 (破碎)
因此,API 22发生了变化。我在API 21和API 22之间看到的唯一实质性差异是对FLAG_LAYOUT_ATTACHED_IN_DECOR标志的支持。 (另请参阅setAttachedInDecor。)此代码确实处理弹出窗口的位置,因此可能与此问题有关。 (我不再相信这是真的。)
我还发现this也可能是相关的。 (也许......)
setClippingEnabled()
适用于API 22-26,允许预览键弹出键盘布局的边界。除了使用反射之外,我还没有找到解决问题的方法。
虽然新的约束行为可能是预期的行为,但这可能有资格获得错误报告。
以下是展示该问题的API 26视频,然后我在mClippingEnabled
中将false
标记设置为PopupWindow.java
并显示已更正的行为。
答案 1 :(得分:1)
在这个问题上花了好几个小时之后,我终于找到了一个我觉得合情合理的解决方案。在自定义InputMethodService
中,维护对KeyboardView的引用,mKeyboardView
,然后覆盖onStartInputView()
。然后,抓住KeyboardView的父级,在其顶部边界应用一些填充,最后使用此修改后的父级布局在KeyboardView上调用setPopupParent()
。这是我的代码:
@Override
public void onStartInputView(EditorInfo info, boolean restarting){
ViewGroup originalParent = (ViewGroup) mKeyboardView.getParent();
if (originalParent != null) {
originalParent.setPadding(0,LAYOUT_PADDING, 0, 0);
mKeyboardView.setPopupParent(originalParent);
}
}
您可以根据存在此问题的API过滤此重写方法的行为。
感谢唐珂提及setPopupParent()
。您可以尝试覆盖不同的方法并使用相同的逻辑,但是,您不能在onCreateInputView()
中执行此操作,因为还没有创建KeyboardView的父级。
答案 2 :(得分:1)
对于将来来这里的人,我建议不要使用KeyboardView
。至少在撰写本文时(API 27),它已经很长时间没有更新。上述问题中描述的问题只是其中的一个缺点。
这是更多的工作,但您可以将自己的自定义视图用作键盘。我在this answer结束时描述了这个过程。
在自定义键盘中创建弹出预览窗口时,需要调用popupWindow.setClippingEnabled(false)
才能让弹出窗口显示在Android API 22+的键盘上方。 (感谢this answer提供的见解。)
以下是我最近的一个项目的背景示例。
private void layoutAndShowPopupWindow(Key key, int xPosition) {
popupWindow = new PopupWindow(popupView,
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
popupWindow.setClippingEnabled(false);// <-- let popup display above keyboard
int location[] = new int[2];
key.getLocationInWindow(location);
int measureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
popupView.measure(measureSpec, measureSpec);
int popupWidth = popupView.getMeasuredWidth();
int spaceAboveKey = key.getHeight() / 4;
int x = xPosition - popupWidth / popupView.getChildCount() / 2;
int y = location[1] - popupView.getMeasuredHeight() - spaceAboveKey;
popupWindow.showAtLocation(key, Gravity.NO_GRAVITY, x, y);
// using popupWindow.showAsDropDown(key, 0, yOffset) might be
// easier than popupWindow.showAtLocation()
}