PopupPanel是GWT写的(akhem)很久以前的一个类(这就是为什么它太糟糕了),允许弹出内容的弹出窗口。其中一个选项是autoHide,如果在弹出窗口之外有某个事件,它会关闭弹出窗口。除了Safari Mobil(SM)之外,它适用于任何事情。原因是SM不触发点击事件。它会触发触摸事件。 PopupPanel被硬编码以查找ClickEvents。
具体来说,代码说:
case Event.ONMOUSEDOWN:
...
if (!eventTargetsPopupOrPartner && autoHide) {
hide(true);
...
显然这不完整,还应包括Event.ONTOUCHSTART
问题是,所有方法和字段都是私有的,所以我无法添加此功能。这是GWT团队的一个大嘘声,但并不是真正的关注,因为我可以创建自己的类并复制PopupPanel的内容。最大的问题是nativeEventPreview不捕获Touch事件!
我尝试将以下内容添加到事件预览中:
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;
}
}
};
“弹出窗口”是PopupPanel,我试图关闭外部触摸事件。 令人遗憾的是,在地球上的任何其他浏览器中进行测试时鼠标都能正常工作,但在iPad上却没有。
我尝试的另一件事是在PopupPanel的玻璃上添加一个TouchStartHandler(它背后的灰色外观)。我希望我可以通过这种方式捕捉触摸事件,但我无法在玻璃上触发事件,因为它以某种有趣的方式附加到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();
}
}
}
在我看来,这应该有用,但事实并非如此。我不知道为什么。欢迎任何想法或建议。感谢。
答案 0 :(得分:7)
这里没有足够的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
);
}-*/;
}