使用大量文本字段滚动VBox

时间:2017-06-06 19:25:55

标签: mobile javafx gluon

我在Scrollpane中的VBox中有很多Textfields。滚动和触摸文本字段时,它只会抓住焦点。因此无法实现平滑滚动。如果没有不必要的重点放在任何文本字段上,我怎么能得到它很好的滚动。在滚动时我是否需要在文本字段中使用事件?

2 个答案:

答案 0 :(得分:1)

这是一种可能的解决方案,用于您想要滚动一长串文本字段而不让它们获得焦点,直到您完全停止滚动,并且显然想要选择其中一个文本字段。

它基于自定义的“按住”活动,受到question的启发。

我们的想法是将TextField控件捆绑在HBox中,并使用容器的鼠标透明属性禁用对控件的访问。

然后,每当您点击容器时,如果按下足够长的容器,容器将提供对控件的访问权限,键盘将显示出来。否则,您将继续滚动,但不显示键盘。

我将仅在iOS上使用此question中提及的KeyboardService

public class BasicView extends View {

    public BasicView(String name) {
        super(name);

        setTop(new Button("Button"));

        VBox controls = new VBox(15.0);

        controls.setAlignment(Pos.CENTER);

        ScrollPane pane = new ScrollPane(controls);
        controls.prefWidthProperty().bind(pane.widthProperty().subtract(20));

        for (int i = 0; i < 100; i++) {
            final Label label = new Label("TextField " + (i + 1));
            final TextField textField1 = new TextField();
            HBox.setHgrow(textField1, Priority.ALWAYS);
            HBox box = new HBox(10, label, textField1);
            box.setMouseTransparent(true);

            box.setAlignment(Pos.CENTER_LEFT);
            box.setPadding(new Insets(5));
            controls.getChildren().add(box);
        }

        addPressAndHoldHandler(controls, Duration.millis(300), eStart -> {
                for (Node box : controls.getChildren()) {
                    box.setMouseTransparent(true);
                }
            }, eEnd -> {
                for (Node box : controls.getChildren()) {
                    if (box.localToScene(box.getBoundsInLocal()).contains(eEnd.getSceneX(), eEnd.getSceneY())) {
                        box.setMouseTransparent(false);
                        ((HBox) box).getChildren().get(1).requestFocus();
                        break;
                    }
                }
            });
        setCenter(pane);

        // iOS only
        Services.get(KeyboardService.class).ifPresent(keyboard -> {
            keyboard.visibleHeightProperty().addListener((obs, ov, nv) -> {
                if (nv.doubleValue() > 0) {
                    for (Node box : controls.getChildren()) {
                        Node n1 = ((HBox) box).getChildren().get(1);
                        if (n1.isFocused()) {
                            double h = getScene().getHeight() - n1.localToScene(n1.getBoundsInLocal()).getMaxY();
                            setTranslateY(-nv.doubleValue() + h);
                            break;
                        }
                    }
                } else {
                    setTranslateY(0);
                }
            });
        });
    }

    @Override
    protected void updateAppBar(AppBar appBar) {
        appBar.setNavIcon(MaterialDesignIcon.MENU.button(e -> System.out.println("Menu")));
        appBar.setTitleText("Scrolling over TextFields");
    }

    private void addPressAndHoldHandler(Node node, Duration holdTime, 
            EventHandler<MouseEvent> handlerStart, EventHandler<MouseEvent> handlerEnd) {
        class Wrapper<T> { 
            T content; 
        }

        Wrapper<MouseEvent> eventWrapper = new Wrapper<>();

        PauseTransition holdTimer = new PauseTransition(holdTime);
        holdTimer.setOnFinished(event -> handlerEnd.handle(eventWrapper.content));

        node.addEventHandler(MouseEvent.MOUSE_PRESSED, event -> {
            handlerStart.handle(event);
            eventWrapper.content = event;
            holdTimer.playFromStart();
        });
        node.addEventHandler(MouseEvent.MOUSE_RELEASED, event -> holdTimer.stop());
        node.addEventHandler(MouseEvent.DRAG_DETECTED, event -> holdTimer.stop());
    }
}

请注意,我在顶部添加了一个按钮,以便在您显示视图时将焦点放在第一位。

每当您点击/点按controls VBox时,它会将所有鼠标框设为透明:box.setMouseTransparent(true);,然后开始PauseTransition

如果在300毫秒之前有鼠标释放或鼠标拖动(可以在方便时更改),过渡将停止。否则,在300毫秒后,它会将框设置为box.setMouseTransparent(false);,并将焦点设置在TextField上,此时键盘将显示。

答案 1 :(得分:0)

这是一个我用于你描述目的的课程:

public class MouseClickedFilter{

    private final Node                       observableNode;

    private BooleanProperty                  scrolling          = new ReadOnlyBooleanWrapper(false);

    private EventHandler<? super MouseEvent> dragDetectedFilter = e -> scrolling.set(true);
    private EventHandler<? super MouseEvent> mouseExitedHandler = e -> scrolling.set(false);

    private EventHandler<? super MouseEvent> mouseClickedFilter = evt ->
                                                                    {
                                                                        if (scrolling.get()) {
                                                                            evt.consume();
                                                                            scrolling.set(false);
                                                                        }
                                                                    };

    private boolean                          listenersEnabled;

    public MouseClickedFilter(Node observableNode) {
        this.observableNode = observableNode;
    }

    public void activate() {
        if (!listenersEnabled) {
            observableNode.addEventFilter(MouseEvent.DRAG_DETECTED, dragDetectedFilter);
            observableNode.addEventHandler(MouseEvent.MOUSE_EXITED, mouseExitedHandler);
            observableNode.addEventFilter(MouseEvent.MOUSE_CLICKED, mouseClickedFilter);
        }
    }

    public void deactivate() {
        if (listenersEnabled) {
            observableNode.removeEventFilter(MouseEvent.DRAG_DETECTED, dragDetectedFilter);
            observableNode.removeEventHandler(MouseEvent.MOUSE_EXITED, mouseExitedHandler);
            observableNode.removeEventFilter(MouseEvent.MOUSE_CLICKED, mouseClickedFilter);
        }
    }

    public final ReadOnlyBooleanProperty scrollingProperty() {
        return scrolling;
    }

    public final boolean isScrolling() {
        return scrolling.get();
    }

}

ObservableNode是您的ScrollPane,其中包含textFields