Java 具有不同单元格高度的listview
我正在尝试创建一个Java 具有不同单元格高度的listview,java,listview,javafx,Java,Listview,Javafx,我正在尝试创建一个列表视图,其中所选单元格具有不同的UI(分别具有不同的高度)。单元格在FXML中声明,并创建自定义控件(DisplayRowDefault和DisplayRowSelected)以加载相应的FXML文件 我还设置了一个单元工厂,在那里我可以管理单元的渲染,具体取决于是否选中该单元 listView.setCellFactory(lv -> new ListCell<>() { private DisplayRowSelected selecte
列表视图
,其中所选单元格具有不同的UI(分别具有不同的高度)。单元格在FXML
中声明,并创建自定义控件(DisplayRowDefault
和DisplayRowSelected
)以加载相应的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);
}
}
}
);
编辑: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();
}
}
公共类示例扩展应用程序{
私有类SelectedCell扩展VBox{
公共选择单元格(){
getChildren().add(新标签(“--”);
getChildren().add(新标签(“选定单元格”);
getChildren().add(新标签(“--”);
}
}
私有类DefaultCell扩展VBox{
公共默认单元格(){
getChildren().add(新标签(“默认单元格”);
}
}
公共静态void main(字符串[]args){
发射(args);
}
@凌驾
公共无效开始(阶段primaryStage){
列表项=列表项(“A项”、“B项”、“C项”、“D项”);
ListView ListView=新建ListView();
listView.getItems().setAll(项);
setCellFactory(lv->new ListCell()){
private SelectedCell SelectedCell=新建SelectedCell();
私有DefaultCell DefaultCell=新的DefaultCell();
@凌驾
受保护的void updateItem(字符串s,布尔值b){
super.updateItem(s,b);
如果(s==null | | b){
setContentDisplay(仅限ContentDisplay.TEXT_);
设置图形(空);
}
否则{
setGraphic(isSelected()?selectedCell:defaultCell);
setContentDisplay(仅限ContentDisplay.GRAPHIC_);
}
}
});
场景=新场景(listView,200500);
初级阶段。场景(场景);
primaryStage.show();
}
}
虽然通过明确询问prefHeight
(我在问题中提到)的解决方案有效,但这不是一个好的解决方案。原因是单个节点的维度取决于放置它们的上下文。因此,不能总是确定prefHeight
值
通过设计,ListView
被设计为在编辑模式下,单元格使用不同的用户界面,更改模式会导致正确地重新计算单元格大小。因此,我选择在更改选择时开始/停止编辑当前单元格的方法
这是我找到的解决方案,它工作正常:
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();
}
}
公共类示例扩展应用程序{
私有类SelectedCell扩展VBox{
公共选择单元格(){
getChildren().add(新标签(“--”);
getChildren().add(新标签(“选定单元格”);
getChildren().add(新标签(“--”);
}
}
私有类DefaultCell扩展VBox{
公共默认单元格(){
getChildren().add(新标签(“默认单元格”);
}
}
公共静态void main(字符串[]args){
发射(args);
}
@凌驾
公共无效开始(阶段primaryStage){
列表项=列表项(“A项”、“B项”、“C项”、“D项”);
ListView ListView=新建ListView();
listView.getItems().setAll(项);
listView.setEditable(true);
setCellFactory(lv->new ListCell()){
private SelectedCell SelectedCell=新建SelectedCell();
私有DefaultCell DefaultCell=新的DefaultCell();
{
selectedProperty().addListener((可观察、旧值、新值)->{
if(oldValue!=null&&oldValue){
取消编辑();
}
if(newValue!=null&&newValue){
startEdit();
}
});
}
@凌驾
公开作废已启动IT(){
super.startEdit();
setGraphic(selectedCell);
}
@凌驾
公共作废取消编辑(){
如果(!isSelected()){
super.cancelEdit();
设置图形(默认单元格);
}
}
@凌驾
受保护的void updateItem(字符串s,布尔值b){
super.updateItem(s,b);
如果(s==null | | b){
setContentDisplay(仅限ContentDisplay.TEXT_);
设置图形(空);
}
否则{
setGraphic(IsEdit()?selectedCell:defaultCell);
setContentDisplay(仅限ContentDisplay.GRAPHIC_);
}
}
});
场景=新场景(listView,200500);
初级阶段。场景(场景);
primaryStage.show();
}
}
如注释中所述,这可能是一个bug(或者不是—单元格有许多属性,它们之间的相互作用没有完全指定)。黑客的解决办法-这里:触发假编辑转换或手动设置高度-通常是需要的
侦听所选属性时的假编辑转换会破解此问题,这一事实表明我们需要在更改通知链中“更早”(比updateItem早)更新图形,即当所选属性发生更改时:
- 要挂接的方法(而不是手动侦听)是
updateSelected(布尔)
- 根据需要覆盖并更改图形
代码片段:
@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)方法并根据需要设置单元格的图形:我没有仔细查看,但从表面上看,它可能会有所帮助。@kleopatra,readyhmm。。很好,你找到了一个解决办法:)不过,想知道
@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);
}
}