#gwt #touch #mobile-safari
#gwt #коснитесь #mobile-safari
Вопрос:
PopupPanel — это класс в GWT, написанный (кхм) давным-давно (вот почему он такой отстой), который позволяет показывать всплывающие окна с содержимым. Одним из вариантов является автоматическое скрытие, когда при наличии определенного события за пределами всплывающего окна всплывающее окно закрывается. Это хорошо работает на чем угодно, кроме Safari Mobil (SM). Причина в том, что SM не запускает события нажатия при касании. Она запускает события касания. Всплывающая панель жестко запрограммирована для поиска событий нажатия.
В частности, в коде говорится:
case Event.ONMOUSEDOWN:
...
if (!eventTargetsPopupOrPartner amp;amp; autoHide) {
hide(true);
...
Очевидно, что это не завершено, и оно также должно включать событие.ONTOUCHSTART
Проблема в том, что все методы и поля являются закрытыми, поэтому я не могу добавить эту функциональность. Это большая похвала со стороны команды GWT, но на самом деле не вызывает беспокойства, поскольку я мог бы просто создать свой собственный класс и скопировать содержимое PopupPanel. Большая проблема в том, что nativeEventPreview не фиксирует события касания!
Я попытался добавить следующее в предварительный просмотр событий следующее:
private static NativePreviewHandler nativePreviewHandler = new NativePreviewHandler() {
public void onPreviewNativeEvent(NativePreviewEvent event) {
Event nativeEvent = Event.as(event.getNativeEvent());
switch (nativeEvent.getTypeInt()) {
case Event.ONTOUCHSTART:
case Event.ONMOUSEDOWN:
EventTarget target = nativeEvent.getEventTarget();
if (!Element.is(target) || !popup.getElement().isOrHasChild(Element.as(target))) {
popup.hide();
} break;
}
}
};
Где ‘popup’ — это всплывающая панель, которую я пытаюсь закрыть при внешних событиях касания.
Печально, что это работает при нажатии мыши при тестировании в любом другом браузере на Земле, но не на iPad.
Еще одна вещь, которую я попробовал, — это добавить TouchStartHandler в стекло всплывающей панели (серая штука за ней). Я надеялся, что смогу таким образом перехватывать события касания, но мне не удалось запустить события в glass, поскольку он каким-то забавным образом привязан к DOM. Мой код:
private static class ProperPopupPanel extends PopupPanel {
public ProperPopupPanel() {
super();
}
void setHideOnGlassTouch() {
setGlassEnabled(true);
TouchableLabeThatDoesntCrashOnWrap glass = new TouchableLabeThatDoesntCrashOnWrap(getGlassElement());
glass.addTouchStartHandler(new TouchStartHandler() {
@Override
public void onTouchStart(TouchStartEvent event) {
hide();
}
});
glass.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
hide();
}
});
}
private class TouchableLabeThatDoesntCrashOnWrap extends Label {
public TouchableLabeThatDoesntCrashOnWrap(Element element) {
super(element);
super.onAttach();
}
}
}
На мой взгляд, это должно сработать, но этого не происходит. Я не знаю почему. Любые идеи или предложения приветствуются. Спасибо.
Ответ №1:
Здесь недостаточно пользователей GWT… ну, я создал свой собственный класс, который добавляет обработчики прикосновений через JSNI …
/**
* Overwrite of the usual PopupPanel with a modification that this one
* works well on touch-enabled browsers.
* @author McTrafik
*/
public class ProperPopupPanel extends PopupPanel {
////////////////////////////////////////////////////////////
/////////// OVERRIDES //////////////////////////////////////
////////////////////////////////////////////////////////////
public ProperPopupPanel() {
super();
setTouchListener();
}
@Override
public void hide() {
super.hide();
removeTouchListener();
}
@Override
public void show() {
super.show();
addTouchListener();
}
////////////////////////////////////////////////////////////
/////////// NANDLERS ///////////////////////////////////////
////////////////////////////////////////////////////////////
protected JavaScriptObject touchHandler;
/**
* Handle a touch event that happened while the popup is open.
* @param event - The event to handle
*/
protected void handleTouchEvent(Event event) {
// Check to see if the events should be firing in the first place.
if (!isShowing()) {
removeTouchListener();
return;
}
// Check if the event happened within the popup
EventTarget target = event.getEventTarget();
if (!Element.is(target) || !getElement().isOrHasChild(Element.as(target))) {
// Stop event if the popup is modal
if (isModal()) event.preventDefault();
// Close the popup if the event happened outside
if (isAutoHideEnabled()) {
hide(true);
removeTouchListener();
}
}
};
/**
* Create a touchHandler that knows how to point to this instance.
* Without it there's a cast exception that happens.
*/
protected native void setTouchListener() /*-{
var caller = this;
this.@[package].ProperPopupPanel::touchHandler = function(event) {
caller.@[package].ProperPopupPanel::handleTouchEvent(Lcom/google/gwt/user/client/Event;)(event);
}
}-*/;
/**
* Add a touch listener that will listen to touch events.
*/
protected native void addTouchListener() /*-{
$doc.addEventListener(
"touchstart",
this.@[package].ProperPopupPanel::touchHandler,
true
);
$doc.addEventListener(
"MozTouchDown",
this.@[package].ProperPopupPanel::touchHandler,
true
);
}-*/;
/**
* Remove the touch listeners
*/
protected native void removeTouchListener() /*-{
$doc.removeEventListener(
"touchstart",
this.@[package].ProperPopupPanel::touchHandler,
true
);
$doc.removeEventListener(
"MozTouchDown",
this.@[package].ProperPopupPanel::touchHandler,
true
);
}-*/;
}