java - 具有不同单元格高度的 ListView

标签 java listview javafx

我正在尝试创建一个 ListView,其中所选单元格具有不同的 UI(分别具有不同的高度)。单元格在 FXML 中声明,并创建自定义控件(DisplayRowDefaultDisplayRowSelected)以加载相应的 FXML 文件.

我还设置了一个单元格工厂,根据它是否被选中来管理单元格的渲染。

listView.setCellFactory(lv -> new ListCell<>() {
        private DisplayRowSelected selectedGraphics;
        private DisplayRowDefault defaultGraphics;

        {
            defaultGraphics = new DisplayRowDefault();
            selectedGraphics = new DisplayRowSelected();
        }

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

            if(empty || item == null) {
                setContentDisplay(ContentDisplay.TEXT_ONLY);
                setGraphic(null);
            }
            else {
                selectedGraphics.setIndex(getListView().getItems().indexOf(item));
                selectedGraphics.setItem(item);

                setGraphic(isSelected() ? selectedGraphics : defaultGraphics);
                setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
            }
        }
    }
);

除单元格大小保持不变外,一切都“完美”。

编辑:我找到了问题的解决方案。重写 computePrefHeight 时,单元格会正确调整大小。此方法的缺点是必须显式指定 prefHeight。

listView.setCellFactory(lv -> new ListCell<>() {
        private DisplayRowSelected selectedGraphics;
        private DisplayRowDefault defaultGraphics;

        {
            defaultGraphics = new DisplayRowDefault();
            defaultGraphics.setPrefHeight(50);

            selectedGraphics = new DisplayRowSelected();
            selectedGraphics.setPrefHeight(100);
        }

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

            if(empty || item == null) {
                setContentDisplay(ContentDisplay.TEXT_ONLY);
                setGraphic(null);
            }
            else {
                selectedGraphics.setIndex(getListView().getItems().indexOf(item));
                selectedGraphics.setItem(item);

                setGraphic(isSelected() ? selectedGraphics : defaultGraphics);
                setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
            }

            setPrefHeight(Region.USE_COMPUTED_SIZE);
        }

        @Override
        protected double computePrefHeight(double v) {
            if(getContentDisplay() == ContentDisplay.GRAPHIC_ONLY) {
                return isSelected() ? selectedGraphics.getPrefHeight() : defaultGraphics.getPrefHeight();
            }

            return super.computePrefHeight(v);
        }
    }
);

编辑:MCVE

public class Sample extends Application {
    private class SelectedCell extends VBox {
        public SelectedCell() {
            getChildren().add(new Label("---"));
            getChildren().add(new Label("Selected Cell"));
            getChildren().add(new Label("---"));
        }
    }

    private class DefaultCell extends VBox {
        public DefaultCell() {
            getChildren().add(new Label("Default Cell"));
        }
    }

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) {
        List<String> items = List.of("Item A", "Item B", "Item C", "Item D");

        ListView<String> listView = new ListView<>();
        listView.getItems().setAll(items);

        listView.setCellFactory(lv -> new ListCell<>() {
            private SelectedCell selectedCell = new SelectedCell();
            private DefaultCell defaultCell = new DefaultCell();

            @Override
            protected void updateItem(String s, boolean b) {
                super.updateItem(s, b);

                if(s == null || b) {
                    setContentDisplay(ContentDisplay.TEXT_ONLY);
                    setGraphic(null);
                }
                else {
                    setGraphic(isSelected() ? selectedCell : defaultCell);
                    setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
                }
            }
        });

        Scene scene = new Scene(listView, 200, 500);

        primaryStage.setScene(scene);
        primaryStage.show();
    }
}

最佳答案

如评论中所述,这可能是一个错误(也可能不是 - 一个单元格具有许多属性,并且它们的相互作用未完全指定)。 Hacky 解决方法 - 这里:触发假编辑转换或手动设置高度 - 通常是需要的。

监听选定属性时的假编辑转换破解了问题表明我们需要在更改通知链中“更早”(比 updateItem)更新图形,即选定更改时:

  • Hook (而不是手动监听)的方法是 updateSelected(boolean)
  • 根据需要覆盖和更改图形

一段代码:

@Override
public void updateSelected(boolean selected) {
    super.updateSelected(selected);
    setGraphic(selected ? selectedCell : defaultCell);
}



@Override
protected void updateItem(String s, boolean b) {
    super.updateItem(s, b);

    if(s == null || b) {
        setContentDisplay(ContentDisplay.TEXT_ONLY);
        setGraphic(null);
    }
    else {
        setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
        setGraphic(isSelected() ? selectedCell : defaultCell);
    }
}

覆盖单元格的 updateSelected(boolean) 方法并根据需要设置单元格的图形:

关于java - 具有不同单元格高度的 ListView ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57592354/

相关文章:

java - 当我将 78.9 插入 Mysql(使用 JDBC)时,它会四舍五入为 79 吗?这是正常的吗

java - java JRE tarball 和 EXE 有什么区别

java - 将两个 ToggleButtons 绑定(bind)到一个 BooleanProperty

java - 场景构建器预览和执行中的程序之间的不同布局

java - 为什么下面的简单 Java 代码块(打印 Hello World )会引发编译错误?

java - 如何从predix通过WebSocket获取时间序列?

Android ListView布局参数集

Android 棉花糖 ListView 滚动变得模糊

带有图像错误的 Android 抽屉导航

java - 在 JAVAFX TableView 中设置值 - 对象与另一个对象