-
Notifications
You must be signed in to change notification settings - Fork 38
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Smooth scrolling #27
Comments
Now that I've documented the code in #33, I don't know if your Instead, I'd suggest the code does something similar to the RichTexfFX approach of suspending a value when the view is being updated and resuming it when its finished. |
Can you give a standalone test that demonstrates this jerkiness? I'm assuming the solution would be to wrap the |
Still no support for smooth scrolling? |
What happens when you try your method on a VirtualFlow ? |
2021-03-21_14-07-36.mp4As you can see the handler in never executed with the VirtualizedScrollPane.
|
Here you go, try this slightly modified version of the code you provided: // Changed method signature to use VirtualFlow and its estimated scroll property directly
private static void customScrolling( VirtualFlow<?,?> flowPane, Var<Double> scrollDirection ) {
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 = {1};
final double[] derivatives = new double[frictions.length];
Timeline timeline = new Timeline();
final EventHandler<MouseEvent> dragHandler = event -> timeline.stop();
final EventHandler<ScrollEvent> scrollHandler = event -> {
if (event.getEventType() == ScrollEvent.SCROLL) {
System.out.println("Smooth Scrolling");
int 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();
}
};
// Changed this to get ScrollEvents to work, "Smooth Scrolling" prints now :-)
flowPane.addEventHandler(MouseEvent.DRAG_DETECTED, dragHandler);
flowPane.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];
// Changed this as values aren't between 0 & 1
scrollDirection.setValue(scrollDirection.getValue() + dy);
if (Math.abs(dy) < 0.001) {
timeline.stop();
}
}));
timeline.setCycleCount(Animation.INDEFINITE);
} |
Sorry the method signature can be reduced to: private static void customScrolling( VirtualFlow<?,?> flowPane, Var<Double> scrollDirection ) which then is invoked with:
|
@Jugen Hello, sorry for the late response.
2021-04-11.12-41-49_Trim.mp4EDIT: I was wondering if I could fix it by changing the type of handler... Yep, everything works now public static void setSmoothScrolling(VirtualFlow<?, ?> flow, Var<Double> scrollDirection) {
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 = {1};
final double[] derivatives = new double[frictions.length];
Timeline timeline = new Timeline();
final EventHandler<MouseEvent> dragHandler = event -> {
System.out.println("STOP!");
timeline.stop();
};
final EventHandler<ScrollEvent> scrollHandler = event -> {
if (event.getEventType() == ScrollEvent.SCROLL) {
System.out.println("Smooth Scrolling");
int 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 (flow.getParent() != null) {
flow.getParent().addEventFilter(MouseEvent.DRAG_DETECTED, dragHandler);
}
flow.parentProperty().addListener((observable, oldValue, newValue) -> {
if (oldValue != null) {
oldValue.removeEventFilter(MouseEvent.DRAG_DETECTED, dragHandler);
}
if (newValue != null) {
newValue.addEventFilter(MouseEvent.DRAG_DETECTED, dragHandler);
}
});
flow.addEventFilter(MouseEvent.DRAG_DETECTED, dragHandler);
flow.addEventFilter(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];
scrollDirection.setValue(scrollDirection.getValue() + dy);
if (Math.abs(dy) < 0.001) {
timeline.stop();
}
}));
timeline.setCycleCount(Animation.INDEFINITE);
} I changed the handlers to filters and everything seems to work good. public static void setSmoothScrolling(AbstractMFXFlowlessListView<?, ?, ?> listView) {
if (listView.getScene() != null) {
VirtualFlow<?, ?> flow = (VirtualFlow<?, ?>) listView.lookup(".virtual-flow");
setSmoothScrolling(flow, flow.estimatedScrollYProperty());
} else {
listView.skinProperty().addListener(new ChangeListener<>() {
@Override
public void changed(ObservableValue<? extends Skin<?>> observable, Skin<?> oldValue, Skin<?> newValue) {
if (newValue != null) {
VirtualFlow<?, ?> flow = (VirtualFlow<?, ?>) listView.lookup(".virtual-flow");
setSmoothScrolling(flow, flow.estimatedScrollYProperty());
listView.skinProperty().removeListener(this);
}
}
});
}
} |
VirtualFlow calculates a reasonable jump size when using the mouse wheel or scroll bar increment/decrement buttons. This leads to reasonable scrolling behaviour but with large content (e.g. a many page PDF) the scroll amount can be quite large, like 20 pixels or so, and this leads to a jerky feeling when scrolling.
Seeing as how ReactFX has the nice Val.animate() method it would probably be quite easy to fix this. I had a quick go at doing so without hacking Flowless itself but it seems the methods I'd need are all (package) private. Perhaps there's a simple trick to get this; I guess inserting a simple animated val with short duration between the desired scroll position and the actual position is sufficient.
The text was updated successfully, but these errors were encountered: