JavaFX Smooth Scrolling for ListView



我想知道是否有办法调整JavaFX ListView的滚动。

你可能会说它滞后,因为我的收藏太大和/或我的CellFactory太重......只是即使有一小部分字符串,帧速率似乎也太低了......

所以我想知道是否有某个地方的设置或指南可以遵循来实现平滑滚动。

提前谢谢你

这是

JFoenix为ScrollPanes创建的平滑滚动,但针对ListViews略有修改(也适用于JFoenix的JFXListView)

public class JFXSmoothScroll  {

private static ScrollBar getScrollbarComponent(ListView<?> control, Orientation orientation) {
    Node n = control.lookup(".scroll-bar");
    if (n instanceof ScrollBar) {
        final ScrollBar bar = (ScrollBar) n;
        if (bar.getOrientation().equals(orientation)) {
            return bar;
        }
    }
    return null;
}   
public static void smoothScrollingListView(ListView<?> listView, double speed) {
    smoothScrollingListView(listView, speed, Orientation.VERTICAL, bounds -> bounds.getHeight());
}
public static void smoothHScrollingListView(ListView<?> listView, double speed) {
    smoothScrollingListView(listView, speed, Orientation.HORIZONTAL, bounds -> bounds.getHeight());
}
private  static void smoothScrollingListView(ListView<?> listView, double speed, Orientation orientation, Function<Bounds, Double> sizeFunc) {
    ScrollBar scrollBar = getScrollbarComponent(listView, orientation);
    if (scrollBar == null) {
        return;
    }
    scrollBar.setUnitIncrement(5);
    final double[] frictions = {0.99, 0.1, 0.05, 0.04, 0.03, 0.02, 0.01, 0.04, 0.01, 0.008, 0.008, 0.008, 0.008, 0.0006, 0.0005, 0.00003, 0.00001};
    final double[] pushes = {speed};
    final double[] derivatives = new double[frictions.length];
    final double[] lastVPos = {0};
    Timeline timeline = new Timeline();
    final EventHandler<MouseEvent> dragHandler = event -> timeline.stop();
    final EventHandler<ScrollEvent> scrollHandler = event -> {
        scrollBar.valueProperty().set(lastVPos[0]);
        if (event.getEventType() == ScrollEvent.SCROLL) {
            double direction = event.getDeltaY() > 0 ? -1 : 1;
            for (int i = 0; i < pushes.length; i++) {
                derivatives[i] += direction * pushes[i];
            }
            if (timeline.getStatus() == Animation.Status.STOPPED) {
                timeline.play();
            }
        }
        event.consume();
    };
    if (scrollBar.getParent() != null) {
        scrollBar.getParent().addEventHandler(MouseEvent.DRAG_DETECTED, dragHandler);
        scrollBar.getParent().addEventHandler(ScrollEvent.ANY, scrollHandler);
    }
    scrollBar.parentProperty().addListener((o,oldVal, newVal)->{
        if (oldVal != null) {
            oldVal.removeEventHandler(MouseEvent.DRAG_DETECTED, dragHandler);
            oldVal.removeEventHandler(ScrollEvent.ANY, scrollHandler);
        }
        if (newVal != null) {
            newVal.addEventHandler(MouseEvent.DRAG_DETECTED, dragHandler);
            newVal.addEventHandler(ScrollEvent.ANY, scrollHandler);
        }
    });
    timeline.getKeyFrames().add(new KeyFrame(Duration.millis(3), (event) -> {
        for (int i = 0; i < derivatives.length; i++) {
            derivatives[i] *= frictions[i];
        }
        for (int i = 1; i < derivatives.length; i++) {
            derivatives[i] += derivatives[i - 1];
        }
        double dy = derivatives[derivatives.length - 1];
        double size = sizeFunc.apply(scrollBar.getLayoutBounds());
        scrollBar.valueProperty().set(Math.min(Math.max(scrollBar.getValue() + dy / size, 0), 1));
        lastVPos[0] = scrollBar.getValue();
        if (Math.abs(dy) < 1) {
            if (Math.abs(dy) < 0.001) {
                timeline.stop();
            } 
        } 
    }));
    timeline.setCycleCount(Animation.INDEFINITE);       
}
}

这有点笨拙

final double[] lastVPos = {0};

因为由于某种原因,我在触发 ScrollEvent 之前找不到触发器的事件,并在此之前设置了初始滚动值。第一次初始化列表后需要调用方法,否则找不到滚动条

最新更新