【问题标题】:JavaFX ListView does not render enough cells to fill its viewportJavaFX ListView 没有渲染足够的单元格来填充其视口
【发布时间】:2016-11-28 00:54:34
【问题描述】:

我有这个音乐播放应用程序,它以网格形式显示艺术家和专辑。我使用 ListView 和自定义 ListCells 创建了这个网格。但是,ListView 在初始化时似乎不会渲染超过 2 个单元格,即使它的高度足够大,可以根据屏幕大小渲染 3 或 4 行。但是,当前 2 个单元格中的一个悬停在上面时,ListView 会渲染剩余的单元格。请查看下面的链接以了解实际问题。

demo of the issue

我检查了 ListView 的高度,它确实在扩展以填充其父级,所以我相信 ListView 决定哪些单元格需要呈现的方式有些奇怪。我希望找到一种方法来强制 ListView 呈现正确数量的单元格,如果这是根本问题,或者如果我的代码中有错误,那么对此也有一些了解会很棒。我已经在下面发布了我的控制器和我的自定义 ListCell 的代码。

初始化 ListView 的控制器:

public class ArtistsController implements Initializable {

    @FXML
    private ListView<ArrayList<Artist>> grid;

    @Override
    public void initialize(URL location, ResourceBundle resources) {

        List<Artist> artists = Library.getArtists();
        Collections.sort(artists);

        grid.setCellFactory(x -> new ArtistListCell<>());

        ObservableList<ArrayList<Artist>> rows = FXCollections.observableArrayList();
        ArrayList<Artist> row = new ArrayList<>();
        int col;

        for (int i = 0; i < artists.size(); i++) {
            col = i % 5;
            if (col == 0) {
                row = new ArrayList<>();
                rows.add(row);
            }
            row.add(artists.get(i));
        }

        grid.setItems(rows);
    }
}

自定义列表单元:

public class ArtistListCell<T extends ArrayList<Artist>> extends ListCell<T> {

    private T item;

    public ArtistListCell() {
        this.getStyleClass().setAll("artist-list-cell");
    }

    @Override
    protected void updateItem(T item, boolean empty) {
        super.updateItem(item, empty);
        if (empty || item == null) {
            setText(null);
            setGraphic(null);
        } else if (!item.equals(this.item)) {
            this.item = item;
            HBox row = new HBox();
            item.forEach(artist -> {
                VBox cell = createCell(artist);
                row.getChildren().add(cell);
            });
            setGraphic(row);
        }
    }

    private VBox createCell(Artist artist) {

        VBox cell = new VBox();
        Label title = new Label(artist.getTitle());
        ImageView image = new ImageView(artist.getArtistImage());
        image.imageProperty().bind(artist.artistImageProperty());
        VBox imageBox = new VBox();

        title.setTextOverrun(OverrunStyle.CLIP);
        title.setWrapText(true);
        title.setPadding(new Insets(10, 0, 10, 0));
        title.setAlignment(Pos.TOP_LEFT);
        title.setPrefHeight(66);
        title.prefWidthProperty().bind(this.widthProperty().subtract(102).divide(5));

        image.fitWidthProperty().bind(this.widthProperty().subtract(102).divide(5));
        image.fitHeightProperty().bind(this.widthProperty().subtract(102).divide(5));
        image.setPreserveRatio(true);
        image.setSmooth(true);

        imageBox.prefWidthProperty().bind(this.widthProperty().subtract(102).divide(5));
        imageBox.prefHeightProperty().bind(this.widthProperty().subtract(102).divide(5));
        imageBox.setAlignment(Pos.CENTER);
        imageBox.getChildren().add(image);

        cell.getChildren().addAll(imageBox, title);
        cell.setPadding(new Insets(10, 10, 0, 10));
        cell.getStyleClass().add("artist-cell");
        cell.setAlignment(Pos.CENTER);

        cell.setOnMouseClicked(event -> {
            // do something
        });

        cell.setOnDragDetected(event -> {
            // do something
        });

        return cell;
    }
}

【问题讨论】:

  • 图片有多大,如何加载?
  • 它们是 300x300 像素的 .jpg,每个大约 20KB。它们的加载方式如下: Image image = new Image("file path goes here");
  • 可能是加载图像的问题。尝试确保在显示场景之前加载图像,例如通过将它们存储在地图中并将它们放入createCell 并检查这是否会改变行为。 (我猜您现在正在使用图像构造函数在createCell 中创建图像。)此外,如果createCell 方法不是很大,您能否将其添加(或允许重现问题的简化版本)到问题?
  • 好的,createCell 方法的大部分内容我都填写了。此外,图像不会在 createCell 中加载。它们在应用程序启动时加载,然后由 artist.getArtistImage() 检索。

标签: java listview javafx javafx-8


【解决方案1】:

我进行了一项测试,并为艺术家使用单个静态图像体验了这个问题。如果我用一个简单的矩形替换 ListCell 中的行构建,它工作正常,所以瓶颈似乎是构建你的 HBox/VBox 单元格。

在 grid.setItems 之后移动对 setCellFactory 的调用似乎可以解决它。

grid.setItems(rows);
grid.setCellFactory(x -> new ArtistListCell<>());

我会说这样做需要另一个布局通道,而另一种方式则没有正确计算所需的所有信息?

如果需要时间,使用正确的图像加载可能会得到不同的结果。如果是这样,如果您仍在体验,也许使用占位符图像?

【讨论】:

  • 这并没有解决我的问题,但我已将问题缩小到 createCell 中的两行,其中 ImageView 的 fitWidthProperty 和 fitHeightProperty 被绑定。用 setFitWidth 或 setFitHeight 替换其中任何一个似乎会使列表视图加载更多单元格。但是添加了这些绑定,以便网格能够调整大小
  • 也许尝试将 HBox 的大小绑定到 ArtistListCell 的大小,然后将 VBox 单元格绑定到 HBox 的大小,这可能会导致大小更新的级联?它似乎在链条的某个地方跳过了一个,因此绑定中的值永远不会更新。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-03-20
  • 2019-01-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-08
  • 2012-05-06
相关资源
最近更新 更多