键盘覆盖 TextField
Keyboard covers TextField
作为胶子视图的中心节点,我有一个滚动窗格,其中包含 vbox 中的几个文本字段。当这些文本字段之一成为焦点所有者并且键盘出现时,文本字段不会根据键盘布局重新定位,因此它被键盘覆盖。
我试着把
android:windowSoftInputMode="adjustResize"
在 AndroidManifest 中,但没有任何成功。
作为解决方法,我将覆盖文本字段的 y 坐标转换为可见区域。当您按 android 后退按钮隐藏键盘时,文本字段位置将重置为原始状态。我遇到的问题是,无论我在哪里添加侦听器,我都没有收到 android 后退按钮的事件:
view.addEventFilter(MobileEvent.BACK_BUTTON_PRESSED, evt -> eventFilter);
MobileApplication.getInstance().getGlassPane().addEventFilter(MobileEvent.BACK_BUTTON_PRESSED, evt -> eventFilter);
有没有可能处理节点在键盘下的定位,或者获取对键盘本身的引用?
只有层获得 MobileEvent.BACK_BUTTON_PRESSED 事件。一种解决方案是本地化并使用 Android API.
这是我目前能想到的解决方案:
public class PositionAdjuster {
public static void main(String[] args) { launch(args); }
private static final float SCALE = FXActivity.getInstance().getResources().getDisplayMetrics().density;
private Node nodeToAdjust;
private ObservableValue<Node> focusOwner;
private ViewGroup viewGroup;
private Rect currentBounds;
private DoubleProperty height;
private OnGlobalLayoutListener layoutListener;
public PositionAdjuster(Node nodeToAdjust, ObservableValue<Node> focusOwner) {
this.nodeToAdjust = nodeToAdjust;
this.focusOwner = focusOwner;
initLayoutListener();
}
private void initLayoutListener() {
double screenHeight = MobileApplication.getInstance().getScreenHeight();
height = new SimpleDoubleProperty(screenHeight);
height.addListener((ov, n, n1) -> onHeightChanged(n, n1));
layoutListener = () -> height.set(getCurrentHeigt());
viewGroup = FXActivity.getViewGroup();
viewGroup.getViewTreeObserver().addOnGlobalLayoutListener(layoutListener);
currentBounds = new Rect();
}
private float getCurrentHeigt() {
viewGroup.getRootView().getWindowVisibleDisplayFrame(currentBounds);
return currentBounds.height() / SCALE;
}
private void onHeightChanged(Number oldValue, Number newValue) {
double heightDelta = newValue.doubleValue() - oldValue.doubleValue();
if (heightDelta < 0) {
double maxY = getBoundsInScene(nodeToAdjust)).getMaxY();
double currentMaxY = heightDelta + maxY;
double result = currentMaxY- getBoundsInScene(focuseOwner.getValue()).getMaxY();
if (result < 0) {
nodeToAdjust.setTranslateY(result);
}
} else if (heightDelta > 0) {
nodeToAdjust.setTranslateY(0);
}
}
private Bounds getBoundsInScene(Node node) {
return node.localToScene(node.getBoundsInLocal());
}
public void removeListener() {
viewGroup.getViewTreeObserver().removeOnGlobalLayoutListener(layoutListener);
}
}
编辑:
我认为这是一种更直接的方法。之前的版本依赖于 noteToAdjust
的 maxY 等于屏幕的高度,没有考虑例如bottomBar 的存在。现在 focusedNode
的 maxY 位置根据可见屏幕高度进行验证,并且差异用于重新定位其父级。
public AndroidPositionAdjuster(Node parent, ObservableValue<Node> focusOwner) {
this.parent = parent;
this.focusOwner = focusOwner;
initLayoutListener();
}
private void onHeightChanged(Number oldHeight, Number newHeight) {
double heightDelta = newHeight.doubleValue() - oldHeight.doubleValue();
if (heightDelta < 0) {
double maxY = newHeight.doubleValue();
double focusedNodeY = getBoundsInScene(focusOwner.getValue()).getMaxY();
double result = maxY - focusedNodeY;
if (result < 0) {
parent.setTranslateY(result);
}
} else if (heightDelta > 0) {
parent.setTranslateY(0);
}
}
作为胶子视图的中心节点,我有一个滚动窗格,其中包含 vbox 中的几个文本字段。当这些文本字段之一成为焦点所有者并且键盘出现时,文本字段不会根据键盘布局重新定位,因此它被键盘覆盖。 我试着把
android:windowSoftInputMode="adjustResize"
在 AndroidManifest 中,但没有任何成功。
作为解决方法,我将覆盖文本字段的 y 坐标转换为可见区域。当您按 android 后退按钮隐藏键盘时,文本字段位置将重置为原始状态。我遇到的问题是,无论我在哪里添加侦听器,我都没有收到 android 后退按钮的事件:
view.addEventFilter(MobileEvent.BACK_BUTTON_PRESSED, evt -> eventFilter);
MobileApplication.getInstance().getGlassPane().addEventFilter(MobileEvent.BACK_BUTTON_PRESSED, evt -> eventFilter);
有没有可能处理节点在键盘下的定位,或者获取对键盘本身的引用?
只有层获得 MobileEvent.BACK_BUTTON_PRESSED 事件。一种解决方案是本地化并使用 Android API.
这是我目前能想到的解决方案:
public class PositionAdjuster {
public static void main(String[] args) { launch(args); }
private static final float SCALE = FXActivity.getInstance().getResources().getDisplayMetrics().density;
private Node nodeToAdjust;
private ObservableValue<Node> focusOwner;
private ViewGroup viewGroup;
private Rect currentBounds;
private DoubleProperty height;
private OnGlobalLayoutListener layoutListener;
public PositionAdjuster(Node nodeToAdjust, ObservableValue<Node> focusOwner) {
this.nodeToAdjust = nodeToAdjust;
this.focusOwner = focusOwner;
initLayoutListener();
}
private void initLayoutListener() {
double screenHeight = MobileApplication.getInstance().getScreenHeight();
height = new SimpleDoubleProperty(screenHeight);
height.addListener((ov, n, n1) -> onHeightChanged(n, n1));
layoutListener = () -> height.set(getCurrentHeigt());
viewGroup = FXActivity.getViewGroup();
viewGroup.getViewTreeObserver().addOnGlobalLayoutListener(layoutListener);
currentBounds = new Rect();
}
private float getCurrentHeigt() {
viewGroup.getRootView().getWindowVisibleDisplayFrame(currentBounds);
return currentBounds.height() / SCALE;
}
private void onHeightChanged(Number oldValue, Number newValue) {
double heightDelta = newValue.doubleValue() - oldValue.doubleValue();
if (heightDelta < 0) {
double maxY = getBoundsInScene(nodeToAdjust)).getMaxY();
double currentMaxY = heightDelta + maxY;
double result = currentMaxY- getBoundsInScene(focuseOwner.getValue()).getMaxY();
if (result < 0) {
nodeToAdjust.setTranslateY(result);
}
} else if (heightDelta > 0) {
nodeToAdjust.setTranslateY(0);
}
}
private Bounds getBoundsInScene(Node node) {
return node.localToScene(node.getBoundsInLocal());
}
public void removeListener() {
viewGroup.getViewTreeObserver().removeOnGlobalLayoutListener(layoutListener);
}
}
编辑:
我认为这是一种更直接的方法。之前的版本依赖于 noteToAdjust
的 maxY 等于屏幕的高度,没有考虑例如bottomBar 的存在。现在 focusedNode
的 maxY 位置根据可见屏幕高度进行验证,并且差异用于重新定位其父级。
public AndroidPositionAdjuster(Node parent, ObservableValue<Node> focusOwner) {
this.parent = parent;
this.focusOwner = focusOwner;
initLayoutListener();
}
private void onHeightChanged(Number oldHeight, Number newHeight) {
double heightDelta = newHeight.doubleValue() - oldHeight.doubleValue();
if (heightDelta < 0) {
double maxY = newHeight.doubleValue();
double focusedNodeY = getBoundsInScene(focusOwner.getValue()).getMaxY();
double result = maxY - focusedNodeY;
if (result < 0) {
parent.setTranslateY(result);
}
} else if (heightDelta > 0) {
parent.setTranslateY(0);
}
}