Gluon ScrollPane刷新问题

时间:2018-06-18 23:35:34

标签: javafx gluon gluon-mobile javafxports

我在Android中运行了一个消息传递应用程序,其设置类似于setup of the screen 订单如下

<View>
<BorderPane>
  <center>
    <ScrollPane>
       <content>
         <VBox> //issue is here
       </content>
    <ScrollPane>
  <center>
  <bottom>
    <TextField>
  <bottom>
</BorderPane>
</View>

当我使用

将孩子添加到VBox时
VBox.getChildren().add(TextLabel);

ScrollPane获取新的VBox并在屏幕上显示。 但是,当我添加更多子项时,当前屏幕可以适合我通过设置 vvalueProperty();

滚动到ScrollPane的结尾
ScrollPane.vvalueProperty().bind(VBox.heightProperty());

(以上代码对于重新创建问题至关重要)

这在计算机上运行时效果非常好,但在移动设备上我有这个奇怪的问题,当我添加更多的孩子而不是屏幕上可以放置的时候,scrollPane会丢弃VBox。当我点击VBox区域时,屏幕刷新,我在屏幕上获得所需的内容 Video demonstrating ScrollBar issue in gluon

为方便起见,我设置了以下颜色代码

ScrollBar - 红色

VBox - Blue

作为绑定的替代方法,我也试过

 ScrollBar.setVvalue(1.0);

setVvalue()没有相同的问题,但另一方面,这并没有显示视图中的最后一条消息。 现在我尝试了所有可能的组合,包括用FlowPane替换VBox并观察到相同的行为。

1 个答案:

答案 0 :(得分:1)

我可以在Android设备上重现您的问题。就像上面的评论中所讨论的那样,垂直滚动位置的绑定导致了某种竞争状况。

我宁愿删除绑定并提出另一种方法来获得期望的结果,而不是试图找出导致该问题的原因:在这种情况下,绑定是非常严格的条件。

当您尝试通过同一遍操作时,此操作:

vBox.getChildren().add(label);
scrollPane.setVvalue(vBox.getHeight());

您已经注意到并提到滚动位置未正确更新,并且缺少添加到vBox的最后一项。

这很容易解释:将新项目添加到框中时,将调用layoutChildren(),这将花费一些时间。至少需要另一个脉冲才能获得正确的值。

但是由于您尝试立即设置垂直滚动位置,因此值vBox.getHeight()仍将返回旧值。换句话说,您必须稍等片刻才能获得新值。

有几种方法可以做到这一点。最简单的方法是使用监听器来监听框的height属性:

vBox.heightProperty().addListener((obs, ov, nv) -> 
    scrollPane.setVvalue(nv.doubleValue()));

或者,将项目添加到框中后,您可以使用:

vBox.getChildren().add(label);
Platform.runLater(() -> scrollPane.setVvalue(vBox.getHeight()));

但是,这不能保证不会立即进行呼叫。因此,最好改用PauseTransition,在这里您可以控制时间:

vBox.getChildren().add(label);

PauseTransition pause = new PauseTransition(Duration.millis(30));
pause.setOnFinished(f -> scrollPane.setVvalue(vBox.getHeight()));
pause.play();

作为建议,您也可以进行一个不错的过渡以滑入新项目。

替代解决方案

到目前为止,您正在将ScrollPaneVBox结合使用以添加许多项,从而可以滚动到列表中的第一项,但始终将滚动位置保持在底部,因此最后添加的项目是完全可见的。尽管这很好用(上面我的建议是避免绑定),但是您正在向非虚拟化容器中添加许多节点。

我认为有一个更好的选择,使用ListView(或者更好的CharmListView允许标题)。使用正确的CellFactory,您可以拥有完全相同的视觉效果,并且可以直接滚动到最后一项。但是此控件的主要优点是它的virtualFlow,它将在您将更多项目添加到列表的同时为您管理数量有限的节点。

这只是在您的聊天应用程序中使用ListView控件的简短代码段:

ListView<String> listView = new ListView<>();
listView.setCellFactory(p -> new ListCell<String>() {
    private final Label label;
    {
        label = new Label(null, MaterialDesignIcon.CHAT_BUBBLE.graphic());
        label.setMaxWidth(Double.MAX_VALUE);
        label.setPrefWidth(this.getWidth() - 60);
        label.setPrefHeight(30);
    }
    @Override
    protected void updateItem(String item, boolean empty) {
        super.updateItem(item, empty);
        if (item != null && ! empty) {
            label.setText(item);
            label.setAlignment(getIndex() % 2 == 0 ? Pos.CENTER_LEFT : Pos.CENTER_RIGHT);
            setGraphic(label);
        } else {
            setGraphic(null);
        }
    }

});
setCenter(listView);

并添加一个新项目并滚动到它,您只需要:

listView.getItems().add("Text " + (listView.getItems().size() + 1));
listView.scrollTo(listView.getItems().size() - 1);

当然,使用正确的样式,您可以删除行之间的线条,并创建与scrollPane相同的视觉效果。