**Describe the bug**
I use MFXListView with custom cells and cell contents. Basically an icon and 2 labels. My ListView is stretched to the entire screen horizontally. When I change the size of my window, the height of the ListView changes, but when the height of the ListView changes, for some reason it redraws all the old Cells and creates new ones. Because of this, my list starts to flicker and create a bunch of new objects, which is bad for RAM, and I also use FXML for the cell contents, and constantly loading FXML to change the height of the ListView even by one pixel is not very good. The problem also appears when the list is reduced, although it costs nothing to just delete only unnecessary Cells, but it recreates everything.
You can replicate the issues by simply creating a list with custom Cells and trying to change its height.
**Expected behavior**
I expect my cells to be stored in some pool and reused each time it is needed. But not to create a new MFXListCell each time.

In the console you can see how the logs about creating new RemoteModView are running. This is the content of my Cell
1) It's not the library, it's probably a bad implementation on your end. The old component (which is MFXListView) updates all the cells in the viewport when events like this happen. It's not creating new cells, otherwise you would not see the icons either, if you look closely only the text is being recomputed. What you want to do is change the way cells are updated, you need to ensure the update is really needed.
```java
@Override
public void updateItem(T newItem) {
T oldItem = getItem();
// Perform identity or equality check depending on your model
// e.g. if (Objects.equals(oldItem, newItem)) return; // Do not update if same item
setItem(newItem); // Update only if different
}
```
2) I suggest you using the newer implementation which can be found [here](https://github.com/palexdev/VirtualizedFX), beware you'll need Java 21. It's much more reliable and performant.
> 1. It's not the library, it's probably a bad implementation on your end. The old component (which is MFXListView) updates all the cells in the viewport when events like this happen. It's not creating new cells, otherwise you would not see the icons either, if you look closely only the text is being recomputed. What you want to do is change the way cells are updated, you need to ensure the update is really needed.
>
> ```java
> @Override
> public void updateItem(T newItem) {
> T oldItem = getItem();
> // Perform identity or equality check depending on your model
> // e.g. if (Objects.equals(oldItem, newItem)) return; // Do not update if same item
> setItem(newItem); // Update only if different
> }
> ```
>
> 2. I suggest you using the newer implementation which can be found [here](https://github.com/palexdev/VirtualizedFX), beware you'll need Java 21. It's much more reliable and performant.
My implementation looks like this: Get all data from the server -> Download image -> Collect ready data into one object -> Display data. That is, at the moment of drawing the cell, I simply set ready values in the fields. Why the images do not flicker, I do not know. Here is another example in which I use the same principle, but the images flicker too

Thanks for the tip about VirtualizedFX!


New cells are created, that is, my implementation has absolutely nothing to do with it.
That's so weird, it shouldn't happen.
When the height changes a method runs to ensure there are just enough cells to fill the viewport. New cells are created only when there aren't enough or the old state is empty. None of these cases apply to you though, so, I don't know what's going on.
Anyway, like I said, use VirtualizedFX. It's a little harder to use because it offers the building blocks for a list view, but it's easy to assemble and offers some defaults too (Although you may want to make your own cells of you don't want to deal with the extra complexity). You can find some examples in the tests. A little preview:
```java
VFXList<T, C> list = new VFXList<>(
// Model list
// Cell factory
);
// Wrap in a custom scroll pane
VFXScrollPane vsp = list.makeScrollable();
// That's it, add the vsp to your view
```
We won't be able to implement VirtualizedFX, because MaterialFX already uses VirtualizedFX but an older version. And when I try to connect VirtualizedFX everything crashes) And pulling MaterialFX out of the project is not an option because there is a lot of work. @palexdev will it be possible to somehow make friends between MFX and VFX of the new versions?
> We won't be able to implement VirtualizedFX, because MaterialFX already uses VirtualizedFX but an older version. And when I try to connect VirtualizedFX everything crashes) And pulling MaterialFX out of the project is not an option because there is a lot of work. @palexdev will it be possible to somehow make friends between MFX and VFX of the new versions?
Unfortunately no. If you use combo boxes or any other component using the virtual flow then you can't exclude the dependency. I can't even update MaterialFX as the new VirtualizedFX requires Java 21
Is the code available somewhere? I can try debugging it if you want, see if I can fix the old library
Unfortunately, the project is private, so there is no public access to the code. However, we would still appreciate your support. Would you be open to assisting us via a screen-sharing session during a call? Alternatively, we could set up an IntelliJ IDEA "Code with Me" session so that you can take a closer look.
> Unfortunately, the project is private, so there is no public access to the code. However, we would still appreciate your support. Would you be open to assisting us via a screen-sharing session during a call? Alternatively, we could set up an IntelliJ IDEA "Code with Me" session so that you can take a closer look.
Let's go with "Code With Me", my pronunciation is not very good, I'm more comfortable writing
@Lairon1 If the problem still exists in your code, here is the solution. I needed a horizontal list and found that MFXListView can't create that type, even though all the code around that feature is already implemented. So I checked the underlying code and came up with a rather creepy solution (because of one small final field). After that, I noticed this strange bug with cell recreation, and it turned out to be in the OrientationHelper implementation.
For HorizontalHelper, there is one specific line:
```java
this.widthChanged = (observable, oldValue, newValue) -> container.reset();
```
This line constantly recreates _all_ cells on each width change (so, on each pulse, I guess).
In VerticalHelper, there is a similar line
```java
this.heightChanged = (observable, oldValue, newValue) -> container.reset();
```
So, I combined my solution with the new one
This extended MFXListView can be used as a drop-in replacement for MFXListView. It supports orientation changes and has a smart debouncer for cell recreation. It has one limitation: if a node is expanding, there may be some empty space because of the debouncer. But this is still better than lags and cell recreation on each frame.
**! Warning !** This code is for **Java 23** with **Manifold**! You can replace all `.jailbreak()` calls to reflection
```java
public class MFXListViewExt<T> extends MFXListView<T> {
private final ObjectProperty<Orientation> orientation = new SimpleObjectProperty<>(null);
public MFXListViewExt() {
super();
bindOrientation();
}
public MFXListViewExt(ObservableList<T> items) {
super(items);
bindOrientation();
}
@SuppressWarnings({"rawtypes", "unchecked", "deprecation"})
private void bindOrientation() {
SimpleVirtualFlow virtualFlow = super.jailbreak().virtualFlow;
virtualFlow.orientationProperty().bind(orientation);
orientation.addListener((_, _, _) -> {
OrientationHelper orientationHelper = virtualFlow.jailbreak().getOrientationHelper();
if (orientationHelper instanceof OrientationHelper.HorizontalHelper helper) {
replaceListener(
helper,
virtualFlow.getVirtualFlow().widthProperty(),
helper.jailbreak().widthChanged,
changeListener -> helper.jailbreak().widthChanged = changeListener
);
} else if (orientationHelper instanceof OrientationHelper.VerticalHelper helper) {
replaceListener(
helper,
virtualFlow.getVirtualFlow().heightProperty(),
helper.jailbreak().heightChanged,
changeListener -> helper.jailbreak().heightChanged = changeListener
);
}
});
}
@SuppressWarnings("deprecation")
private void replaceListener(OrientationHelper helper, ReadOnlyDoubleProperty property, ChangeListener<? super Number> resetListener, Consumer<ChangeListener<? super Number>> fieldUpdater) {
property.removeListener(resetListener);
PauseTransition debounceTimer = new PauseTransition(Duration.millis(200));
debounceTimer.setOnFinished(_ -> resetListener.changed(property, property.getValue(), property.getValue()));
ChangeListener<Number> smartListener = (_, _, _) -> {
int neededCells = helper.computeCellsNumber();
int actualItems = getItems().size();
int required = Math.min(neededCells, actualItems);
int currentCells = getCells().size();
if (currentCells < required) {
debounceTimer.playFromStart();
} else {
debounceTimer.stop();
}
};
fieldUpdater.accept(smartListener);
property.addListener(smartListener);
}
public Orientation getOrientation() {
return orientation.get();
}
public ObjectProperty<Orientation> orientationProperty() {
return orientation;
}
public void setOrientation(Orientation orientation) {
this.orientation.set(orientation);
}
}
```
@palexdev oh, i see. ty
But there are no info about that in this issue, no any info in main branch and no any migration plan into new alpha. So, i think, my hacky solution may be helpfull for folks that sticks to stable 11.17.0