Tobias L.
Tobias L.

Reputation: 107

How to find out if the user scrolled to the end of the ListView

As the headline already said. How can I find out that the user scrolled to the end of the list view in javafx.

Upvotes: 3

Views: 923

Answers (1)

kleopatra
kleopatra

Reputation: 51525

Elaborating a bit on my comment: looking at the API my first impulse was to register a onScrollTo handler with the list and doStuff() when reaching the end, something like

list.setOnScrollTo(e -> {
    if (e.getScrollTarget() >= list.getItems().size() -1) {
        doStuff(); 
    }  
});

Unfortunate, that doesn't work: the handler is called only if either one of the methods list.scrollTo(int) or list.scrollTo(T). That's documented - but can't think of any use-case where we would need it?

Which leaves the dirty ol' work-around of digging up the ScrollBar from the list's children and listen to its value property (Note: the digging needs to be done after the skin is installed!).

A quick example:

public class ScrollToHandlerList extends Application {
    private final ObservableList<Locale> data =
            FXCollections.observableArrayList(Locale.getAvailableLocales());

    private final ListView<Locale> list = new ListView<>(data);

    @Override
    public void start(Stage stage) {
        stage.setTitle("List ScrollTo Handler " + FXUtils.version());
        Button leftScrollTo = new Button("scrollto last");
        leftScrollTo.setOnAction(e -> {
            // explicit calling notifies the onScrollHandler
            list.scrollTo(list.getItems().size() -1);
        });
        // Would expect a onScrollTo handler getting notified
        // but isn't ...
        list.setOnScrollTo(e -> {
            LOG.info("target/size" + e.getScrollTarget() + " / " + data.size());
        });
        // nor a onScroll handler ...
        list.setOnScroll(e -> {
            LOG.info("" + e);
        });
        HBox root = new HBox(leftScrollTo, list);
        Scene scene = new Scene(root);
        stage.setScene(scene);
        stage.show();

        // dirty: lookup the scrollBar and listener to its value property
        ScrollBar bar = (ScrollBar) list.lookup(".scroll-bar");
        bar.valueProperty().addListener((src, ov, nv) -> {
            LOG.info("change on value " + nv);
            if (nv.doubleValue() == 1.) {
                LOG.info("at max");
            }
        });
    }

    public static void main(String[] args) {
        launch(args);
    }
    @SuppressWarnings("unused")
    private static final Logger LOG = Logger.getLogger(ScrollToHandlerList.class
            .getName());
}

Update

Got additional info via twitter:

  • not notifying about scroll events is intentional, actually the events from the scrollBars are blocked by VirtualFlow
  • there's a solution using public api only, basically making the cell itself aware of reaching the end of the scrolling region

Upvotes: 1

Related Questions