GWT 2.2.0 PopupPanel自动隐藏TOUCH事件

时间:2011-04-06 23:58:27

标签: gwt touch mobile-safari

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();
        }
    }
}

在我看来,这应该有用,但事实并非如此。我不知道为什么。欢迎任何想法或建议。感谢。

1 个答案:

答案 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
         );
    }-*/;


}