带有自定义CellFactory的ListView修剪不可见节点

时间:2017-03-25 13:20:33

标签: java listview layout javafx

我的布局问题

我对ListView有一点问题,我不确定是不是因为我遗漏了一些知识,或者我的方法存在缺陷。不得不承认我还不清楚JavaFX在很多情况下如何处理布局。

ListView trims my attempt at layout

上面的屏幕截图显示了我使用完全相同的代码得到两次的结果,除了在第二个上是一个看不见的形状我用于连贯布局使得调试可见

CellFactory扩展Group所涉及的各个类,我尝试了其他一些Parent到目前为止没有取得多大成功。

如何重现

我没有分享我的StarShapeStarRow和其他一些misc课程(如果有要求,我很乐意),我写了一个重现该问题的样本。该类扩展Application并覆盖start(...)方法:

@Override
public void start(Stage primaryStage) throws Exception {
    final StackPane root = new StackPane();
    final Scene scene = new Scene(root, 400, 600);

    final ListView<Boolean> listView = new ListView<>();
    listView.setCellFactory(this::cellFactory);

    for (int i = 0; i < 5 ; i++) {
        listView.getItems().add(true);
        listView.getItems().add(false);
    }

    root.getChildren().add(listView);

    primaryStage.setScene(scene);
    primaryStage.setTitle("ListView trims the invisible");
    primaryStage.show();
}

其中this::cellFactory

private ListCell<Boolean> cellFactory(ListView<Boolean> listView) {
    return new ListCell<Boolean>() {
        @Override
        protected void updateItem(Boolean item, boolean empty) {
            super.updateItem(item, empty);

            if (empty || item == null) {
                setText(null);
            } else {
                final Rectangle tabShape = new Rectangle();
                tabShape.setHeight(20);
                tabShape.setWidth(40);
                tabShape.setVisible(item);

                final Label label = new Label(item.toString());
                label.setLayoutX(40);

                final Group cellRoot = new Group();
                cellRoot.getChildren().add(tabShape);
                cellRoot.getChildren().add(label);

                setGraphic(cellRoot);
            }
        }
    };
}

以上内容会在ListView<Boolean>个项目前面显示带有黑色形状的true(由于tabShape.setVisible(item);位)。 false项看起来像常规Label对象,好像Group中的隐形形状不存在(但它是)。

结束评论

调试这个,结果是具有不可见形状的组被赋予负布局X属性值。因此,Label控件并未对齐,因为我喜欢它们。当我在setLayoutX之外拨打setLayoutYListView时(不可见的形状强制偏移),它不会发生,但它可能不是唯一的地方它会发生。

发生了什么以及如何避免它?或者,正如我猜测我接近这个错误的一样,什么是正确的方法?换句话说,我应该问的问题是什么呢?

2 个答案:

答案 0 :(得分:13)

@dlatikay's comment开始,不是将占位符项设置为不可见,而是可以通过将其不透明度设置为0.0来使其透明。

从你的问题应用到MCVE,这将通过替换:

来完成
tabShape.setVisible(item);

使用:

tabShape.setOpacity(item ? 1.0 : 0.0);

就用户体验而言,您可以更进一步。而不是设置&#34;非活动&#34;星星完全透明,您可以将它们设置为接近透明,就像在此模型中一样(不透明度设置为0.1):

mockup

我看到的好处是:

  1. 它不仅表示列表中项目的评级,还表示最高评级。
  2. 它避免了零星级列表项的尴尬空白区域。

答案 1 :(得分:4)

  

我猜测我正在接近这个错误的

不,你不是。与所有布局一样,通常有多种方法可以解决同一问题。您的方法实际上是正确的,并且您非常接近工作解决方案。

只需1行更改即可实现您的目标。也就是说,将Group更改为HBox

HBox确保元素一个接一个地水平排序。它们还允许隐形元素占用空间。

我还注释了一行:label.setLayoutX(40)。我这样做是因为HBox不会尊重此设置,实际上您并不需要它。它将根据需要自动水平移动元素。

@Override
protected void updateItem(Boolean item, boolean empty) {
    super.updateItem(item, empty);

    if (empty || item == null) {
        setText(null);
    }
    else {
        final Rectangle tabShape = new Rectangle();
        tabShape.setHeight(20);
        tabShape.setWidth(40);
        tabShape.setVisible(item);

        final Label label = new Label(item.toString());
        //label.setLayoutX(40);

        final HBox cellRoot = new HBox();
        cellRoot.getChildren().add(tabShape);
        cellRoot.getChildren().add(label);

        setGraphic(cellRoot);
    }
}

当我进行这些更改时,您的布局将呈现如下:

enter image description here

重要:您的示例和屏幕截图略有不同。您可能希望使用VBox作为明星示例(V代表&#39;垂直&#39;,H代表&#39;水平&#39;)。