Keyboard covers TextField

狂风中的少年 提交于 2019-12-23 03:13:07

问题


As the center node of a gluon view I have a scrollpane which contains several textfields in a vbox. When one of these textfields becomes the focusowner and the keyboard shows up, the textfield doesn't get repositioned according to the layout of the keyboard, so it is left covered by the keyboard. I tried putting

 android:windowSoftInputMode="adjustResize"

in the AndroidManifest, but without any success.

As a workaround I translate the y-coordinates of the covered textfield to the visible area. When you press the android back button to hide the keyboard, the textfields position will be reset to its original state. The issue I'm getting here is that I don't get an event for the android back button, no matter where I add the listener:

 view.addEventFilter(MobileEvent.BACK_BUTTON_PRESSED, evt -> eventFilter); 

 MobileApplication.getInstance().getGlassPane().addEventFilter(MobileEvent.BACK_BUTTON_PRESSED, evt -> eventFilter); 

Is there any possibility to handle the positioning of a node under the keyboard, or to get a reference to the keyboard itself?


回答1:


Only layers get the MobileEvent.BACK_BUTTON_PRESSED event. One solution is to go native and use the Android API.




回答2:


This is the solution I could come up with so far:

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);
    }
}

EDIT:

I think this is a more straightforward approach. The previous version was dependent on the maxY of noteToAdjust to be equal to the height of the screen, not taking into account e.g. the presence of a bottomBar. Now the maxY position of the focusedNode is validated against the visible screen height, and the difference is used to reposition its parent.

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);
    }
}


来源:https://stackoverflow.com/questions/36269682/keyboard-covers-textfield

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!