【问题标题】:listview with different cell height具有不同单元格高度的列表视图
【发布时间】:2019-12-26 18:36:53
【问题描述】:

我正在尝试执行ListView,其中选定的单元格具有不同的用户界面(分别具有不同的高度)。单元格在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();
    }
}

【问题讨论】:

  • 我没有深究,但表面上看来this可能会有所帮助。
  • @kleopatra,准备好了

标签: java listview javafx


【解决方案1】:

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

在侦听所选属性hacks上的假编辑转换的事实问题表明我们需要在更改通知链中更新图形“早期”(比更新),即所选更改时: p >

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

一个代码sn-p:

@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) 方法并根据需要设置单元格的图形:

【讨论】:

  • 简单优雅的解决方案。
  • 谢谢 :) 没有minimal reproducible example 就不会碰到这个问题,很高兴你最终提供了一个。一个非常小的注意事项:更喜欢自我回答以坚持自我提供的示例 - 通过简单的 c&p 更容易测试解决方案(与必须编辑字段名称相比)。是的,我非常懒惰..
【解决方案2】:

虽然通过明确询问prefHeight(我在问题中提到)的解决方案有效,但这不是一个好的解决方案。这样做的原因是单个Nodes 的尺寸取决于它们所在的上下文。因此,prefHeight 值无法始终确定。

根据设计,ListView 的设计使在编辑模式下,单元格使用不同的 UI,并且更改模式会导致正确地重新计算单元格大小。所以我选择在更改选择时开始/停止编辑当前单元格的方法。

这是我找到的解决方案,它可以正常工作:

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.setEditable(true);

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

            {
                selectedProperty().addListener((observable, oldValue, newValue) -> {
                    if (oldValue != null && oldValue) {
                        cancelEdit();
                    }

                    if (newValue != null && newValue) {
                        startEdit();
                    }
                });
            }

            @Override
            public void startEdit() {
                super.startEdit();
                setGraphic(selectedCell);
            }

            @Override
            public void cancelEdit() {
                if(!isSelected()) {
                    super.cancelEdit();
                    setGraphic(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(isEditing() ? selectedCell : defaultCell);
                    setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
                }
            }
        });

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

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

【讨论】:

  • hmm .. 很高兴您找到了解决方法:) 不过,想知道即使列表不可编辑(如您在问题中的示例),也会发生不当行为。对我来说闻起来像一个错误(当属性 - 除了项目,f.i. selected - 被更改时,在 updateItem 中更新 ui 时会出现问题。它已修复,这可能是遗留问题)
  • 确实有效,虚假的可编辑更改似乎会触发列表的“更广泛”的重新布局,而不是选定的更改(绝对是我书中的一个错误) - 为了使其适用于不可编辑的列表,updateItem 应该坚持选择的属性来决定设置哪个图形(否则更新高度但不更新内容,看起来像一个不稳定的布局)
猜你喜欢
  • 2012-12-11
  • 2018-05-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多