I would like to know how to do scrollview swipe effectwhen the mouse is dragged up and down. I am developing a JavaFX application with ListViewand I need to scroll through the list when the user drags the mouse up and down (e.g. iOS contact list).
Also how to add user speed and speed to scroll value?
UPDATED: I have the code here, but it does not work properly ...
import java.util.ArrayList;
import java.util.Arrays;
import javafx.animation.Interpolator;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.animation.TimelineBuilder;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.event.Event;
import javafx.geometry.Pos;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.ScrollEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.FlowPane;
import javafx.util.Duration;
public class Swipe extends ScrollPane {
private static final int INERTIA_DURATION = 2400;
private static final double CLICK_THRESHOLD = 20;
private static final double CLICK_TIME_THRESHOLD = Integer.parseInt(System.getProperty("click", "400"));
private final double width;
private final double height;
private long startDrag;
private long lastDrag;
private long lastDragDelta;
private int startDragX;
private int startDragY;
private int lastDragX;
private int lastDragY;
private int lastDragStepX;
private int lastDragStepY;
private double dragVelocityX;
private double dragVelocityY;
private boolean clickThresholdBroken;
private Timeline inertiaTimeline = null;
private long lastClickTime = -1;
private final boolean isFiredByMe = false;
public Swipe(double width, double height) {
this.width = width;
this.height = height;
init();
}
private void init() {
setPrefSize(width, height);
setPannable(true);
setHbarPolicy(ScrollBarPolicy.NEVER);
setVbarPolicy(ScrollBarPolicy.NEVER);
setEventHandlers();
ContentPane cp = new ContentPane();
setContent(cp);
}
private void setEventHandlers() {
setOnMousePressed((MouseEvent event) -> {
lastDragX = startDragX = (int) event.getX();
lastDragY = startDragY = (int) event.getY();
lastDrag = startDrag = System.currentTimeMillis();
lastDragDelta = 0;
if (inertiaTimeline != null) {
inertiaTimeline.stop();
}
clickThresholdBroken = false;
});
setOnDragDetected((MouseEvent event) -> {
lastDragStepX = (int) event.getX() - lastDragX;
lastDragStepY = (int) event.getY() - lastDragY;
lastDragDelta = System.currentTimeMillis() - lastDrag;
dragVelocityX = (double) lastDragStepX / (double) lastDragDelta;
dragVelocityY = (double) lastDragStepY / (double) lastDragDelta;
lastDragX = (int) event.getX();
lastDragY = (int) event.getY();
lastDrag = System.currentTimeMillis();
final int dragX = (int) event.getX() - startDragX;
final int dragY = (int) event.getY() - startDragY;
double distance = Math.abs(Math.sqrt((dragX * dragX) + (dragY * dragY)));
int scrollDistX = lastDragStepX;
int scrollDistY = lastDragStepY;
if (!clickThresholdBroken && distance > CLICK_THRESHOLD) {
clickThresholdBroken = true;
scrollDistX = dragX;
scrollDistY = dragY;
}
if (clickThresholdBroken) {
Event.fireEvent(event.getTarget(), new ScrollEvent(
ScrollEvent.SCROLL,
scrollDistX, scrollDistY,
scrollDistX, scrollDistY,
event.isShiftDown(), event.isControlDown(), event.isAltDown(), event.isMetaDown(),
true, false,
event.getX(), event.getY(),
event.getSceneX(), event.getSceneY(),
ScrollEvent.HorizontalTextScrollUnits.NONE, 0,
ScrollEvent.VerticalTextScrollUnits.NONE, 0, 0, null));
}
});
setOnMouseReleased((MouseEvent event) -> {
handleRelease(event);
});
setOnMouseClicked((MouseEvent event) -> {
final long time = System.currentTimeMillis();
if (clickThresholdBroken || (lastClickTime != -1 && (time - lastClickTime) < CLICK_TIME_THRESHOLD)) {
event.consume();
}
lastClickTime = time;
});
}
private void handleRelease(final MouseEvent me) {
if (clickThresholdBroken) {
final long time = System.currentTimeMillis() - lastDrag;
dragVelocityX = (double) lastDragStepX / (time + lastDragDelta);
dragVelocityY = (double) lastDragStepY / (time + lastDragDelta);
final int dragX = (int) me.getX() - startDragX;
final int dragY = (int) me.getY() - startDragY;
final long totalTime = System.currentTimeMillis() - startDrag;
final boolean quick = totalTime < 300;
double velocityX = quick ? (double) dragX / (double) totalTime : dragVelocityX;
double velocityY = quick ? (double) dragY / (double) totalTime : dragVelocityY;
final int distanceX = (int) (velocityX * INERTIA_DURATION);
final int distanceY = (int) (velocityY * INERTIA_DURATION);
DoubleProperty animatePosition = new SimpleDoubleProperty() {
double lastMouseX = me.getX();
double lastMouseY = me.getY();
@Override
protected void invalidated() {
final double mouseX = me.getX() + (distanceX * get());
final double mouseY = me.getY() + (distanceY * get());
final double dragStepX = mouseX - lastMouseX;
final double dragStepY = mouseY - lastMouseY;
if (Math.abs(dragStepX) >= 1.0 || Math.abs(dragStepY) >= 1.0) {
Event.fireEvent(me.getTarget(), new ScrollEvent(
ScrollEvent.SCROLL,
dragStepX, dragStepY,
(distanceX * get()), (distanceY * get()),
me.isShiftDown(), me.isControlDown(), me.isAltDown(), me.isMetaDown(),
true, true,
me.getX(), me.getY(),
me.getSceneX(), me.getSceneY(),
ScrollEvent.HorizontalTextScrollUnits.NONE, 0,
ScrollEvent.VerticalTextScrollUnits.NONE, 0,
0, null));
}
lastMouseX = mouseX;
lastMouseY = mouseY;
}
};
inertiaTimeline = TimelineBuilder.create()
.keyFrames(
new KeyFrame(Duration.ZERO, new KeyValue(animatePosition, 0)),
new KeyFrame(Duration.millis(INERTIA_DURATION), new KeyValue(animatePosition, 1d, Interpolator.SPLINE(0.0513, 0.1131, 0.1368, 1.0000)))
).build();
inertiaTimeline.play();
}
}
private class ContentPane extends FlowPane {
private ArrayList getList() {
String[] list = {
"Kerrie Batts", "Raina Huffstutler", "Kip Kukowski", "Trish Sullivan", "Kyla Hollingsworth", "Gearldine Leavy", "Major Langdon", "Avery Rusin", "Hedy Messina", "Audry Felps", "Tianna Robbins", "Marian Tranmer", "Lashaunda Bivona", "Leighann Schwab", "Emanuel Volpe", "Neida Geist", "Edda Placencia", "Olevia Hippe", "Fernando Cohen", "Danette Dorsett"};
ArrayList<String> nameList = new ArrayList();
nameList.addAll(Arrays.asList(list));
return nameList;
}
public ContentPane() {
setPrefSize(215, 271);
ArrayList<String> nameList = getList();
Element[] element = new Element[nameList.size()];
for (int i = 0; i < nameList.size(); i++) {
String name = nameList.get(i);
Element el = element[i] = new Element(210, 25, name);
getChildren().add(el);
}
}
}
private class Element extends AnchorPane {
private double width;
private double height;
private String name;
public Element(double width, double height, String name) {
this.width = width;
this.height = height;
this.name = name;
init();
}
private Label createName() {
Label label = new Label(name);
label.setPrefSize(width, height);
label.setAlignment(Pos.CENTER_LEFT);
AnchorPane.setLeftAnchor(label, 5.0);
label.setStyle("-fx-font-family: Calibri; -fx-font-size: 14;");
return label;
}
private void init() {
setPrefSize(width, height);
getChildren().add(createName());
}
public void setPrefSize(double width, double height) {
this.width = width;
this.height = height;
}
public void setName(String name) {
this.name = name;
}
}
}