I am trying to do a simple Demo about using JavaFX on Mobile using GluonFX Pluging & Attche.
The App, Will be Simply WebApp. The Main problem now is When the user click on any text input field, the Mobile keyboard is shown but most of times the View is not moved to keep the edited text field still shown.
I checked the Attach Service (Keyboard), The code by "José_Pereda" is great. but is not suitable for the full screen webview. because it shift the all view to be visible when the keyboard is up. but this mean that the input field may be out of the screen!
How can i solve this problem I tried to make touch/click event to check the last X,Y from the user and use this value in the keyboard service handler and this works great on Desktop (linux) but on Android phone, no Touchevent on the webview are fired !!
Any help
This is the Main Controller which have all the magic. but the Webview Object is shared in the App
package com.sam.stv.parentsapp;
import com.gluonhq.attach.keyboard.KeyboardService;
import com.gluonhq.attach.util.Platform;
import com.gluonhq.attach.util.Services;
import javafx.animation.Interpolator;
import javafx.animation.TranslateTransition;
import javafx.beans.property.SimpleStringProperty;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.TouchEvent;
import javafx.scene.layout.StackPane;
import javafx.scene.web.WebView;
import javafx.util.Duration;
public class PrimaryController {
WebView webview;
private EventHandler<MouseEvent> handlerForMouse;
private EventHandler<TouchEvent> handlerForTouch;
double lastX;
double lastY;
SimpleStringProperty msg = new SimpleStringProperty("Good Luck!");
ProgressIndicator progressIndicator;// = new ProgressIndicator(); // or you can use ImageView with animated gif
@FXML
StackPane webcontainer;
@FXML
StackPane paneBottom;
@FXML
StackPane paneTop;
@FXML
private void initialize() {
// ========================================= Logging lbl in Mobile
Label lbl = new Label();
lbl.textProperty().bind(msg);
lbl.prefHeight(50);
lbl.prefWidth(200);
paneTop.getChildren().addAll(lbl);
// ========================================= WebView Setup
this.webview = App.getWebview();
webcontainer.getChildren().add(webview);
// ========================================= handling Touching and clicking by
// adding listeners
initHandlers();
handlingTouching();
// ========================================= Attache-Service:=> Virtual Keyboard
// Handling
Services.get(KeyboardService.class).ifPresent(service -> {
service.visibleHeightProperty().addListener((obs, ov, nv) -> doSomethingForKeyboardBasedOnTouch(nv));
});
}
/**
* This method shit the View (webview) upward Based on the last user touch/click
* point position.
*
* @param nv
*/
void doSomethingForKeyboardBasedOnTouch(Number nv) {
Node node = this.webview;
double kh = nv.doubleValue();
double padding = 20;
if (node == null || node.getScene() == null || node.getScene().getWindow() == null) {
return;
}
double tTot = node.getScene().getHeight();
// Original Code :-> node.getLocalToSceneTransform().getTy() + node.getBoundsInParent().getHeight() + 2;
double ty = lastY + padding; // Can not update this value using the last touch event
double y = 1;
Parent root = node.getScene().getRoot();
if (ty > tTot - kh) {
y = tTot - ty - kh;
} else if (kh == 0 && root.getTranslateY() != 0) {
y = 0;
}
if (y <= 0) {
System.out.println(String.format("Moving %s %.2f pixels", root, y));
final TranslateTransition transition = new TranslateTransition(Duration.millis(50), root);
transition.setFromY(root.getTranslateY());
transition.setToY(y);
transition.setInterpolator(Interpolator.EASE_OUT);
transition.playFromStart();
}
}
private void handlingTouching() {
applyTouchClickInput(webcontainer);
applyTouchClickInput(paneBottom);
applyTouchClickInput(paneTop);
applyTouchClickInput(webview);
}
private void applyTouchClickInput(Node drawSurface) {
if (Platform.isAndroid() || Platform.isIOS()) {
// end the path when mouse released event
// drawSurface.setOnTouchReleased(handlerForTouch);
// drawSurface.setOnTouchPressed(handlerForTouch);
// drawSurface.setOnTouchMoved(handlerForTouch);
// drawSurface.addEventFilter(TouchEvent.ANY, handlerForTouch);
// drawSurface.addEventHandler(TouchEvent.ANY, handlerForTouch);
drawSurface.addEventFilter(TouchEvent.TOUCH_MOVED, handlerForTouch);
drawSurface.addEventFilter(TouchEvent.TOUCH_PRESSED, handlerForTouch);
drawSurface.addEventFilter(TouchEvent.TOUCH_RELEASED, handlerForTouch);
// drawSurface.addEventHandler(TouchEvent.TOUCH_MOVED, handlerForTouch);
// drawSurface.addEventHandler(TouchEvent.TOUCH_PRESSED, handlerForTouch);
// drawSurface.addEventHandler(TouchEvent.TOUCH_RELEASED, handlerForTouch);
} else if (Platform.isDesktop()) {
drawSurface.addEventFilter(MouseEvent.MOUSE_CLICKED, handlerForMouse);
}
}
void initHandlers() {
this.handlerForMouse = new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
String log = "Clicking: " + event.getEventType().getName() + " on "
+ event.getTarget().getClass().getSimpleName() + ")--->(" + event.getX() + "," + event.getY()
+ ")";
logging(log);
logTouch(event.getX(), event.getY());
}
};
this.handlerForTouch = new EventHandler<TouchEvent>() {
@Override
public void handle(TouchEvent event) {
String log = "Touching: " + event.getEventType().getName() + " on "
+ event.getTarget().getClass().getSimpleName() + ")--->(" + event.getTouchPoint().getX() + ","
+ event.getTouchPoint().getY() + ")";
logging(log);
logTouch(event.getTouchPoint().getX(), event.getTouchPoint().getY());
}
};
}
void logTouch(double x, double y) {
System.out.println("Set New X & Y (" + lastX + "," + lastY + ")--->(" + x + "," + y + ")");
lastX = x;
lastY = y;
}
public void logging(String log) {
System.out.println("===============================================> General Logging Handler.");
System.out.println(log);
msg.set(log);
}
}
Based on @JosePereda Confirmation that we can not receive the touch event on the Mobile devices.
Then, my work around to bypass that is to inject a Javascript in the webview loading time. this script is recording the touch event and then call a Java method whenever this touch event is done.
The Javascript-Java bridging is not work flexibly as expected, but works