【发布时间】:2016-05-06 01:18:09
【问题描述】:
我想知道是否有办法调整 JavaFX 的 ListView 的滚动。
你可能会说它太迟钝了,因为我的集合太大和/或我的CellFactory 太重......只是帧速率似乎太低,即使是少量字符串......
所以我想知道某处是否有设置或指导方针来实现平滑滚动。
提前谢谢你
【问题讨论】:
标签: java listview optimization javafx smooth-scrolling
我想知道是否有办法调整 JavaFX 的 ListView 的滚动。
你可能会说它太迟钝了,因为我的集合太大和/或我的CellFactory 太重......只是帧速率似乎太低,即使是少量字符串......
所以我想知道某处是否有设置或指导方针来实现平滑滚动。
提前谢谢你
【问题讨论】:
标签: java listview optimization javafx smooth-scrolling
这是JFoenix's smooth scrolling created for 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 之前我找不到触发器并在此之前设置初始滚动值。 方法需要在第一次初始化列表后调用,否则找不到滚动条
【讨论】: