2011-04-06 62 views
3

PopupPanel是很久以前GWT寫的(akhem)中的一個類(這就是爲什麼它吸得太多),允許顯示帶有內容的彈出窗口。其中一個選項是autoHide,如果彈出窗口外有某個事件,它會關閉彈出窗口。除了Safari Mobil(SM)之外,它可以很好地工作。原因是SM不會觸發點擊事件。它觸發觸摸事件。 PopupPanel被硬編碼以尋找ClickEvents。GWT 2.2.0 PopupPanel自動隱藏TOUCH事件

具體而言,編碼說:

case Event.ONMOUSEDOWN: 
    ... 
    if (!eventTargetsPopupOrPartner && autoHide) { 
     hide(true); 
    ... 

顯然,這是不完全的,它還應包括Event.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; 
     }  
      } 
}; 

其中「彈出」是我試圖去結束對外界觸摸事件的PopupPanel。 可悲的是,當在地球上的任何其他瀏覽器中進行測試時,鼠標會失效,但在iPad上不會。

我嘗試的另一件事是添加一個TouchStartHandler到PopupPanel的玻璃杯(背後灰色的東西)。我希望能夠以這種方式捕捉觸摸事件,但是由於它以某種有趣的方式附着到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(); 
     } 
    } 
} 

在我看來,這應該可行,但事實並非如此。我不知道爲什麼。歡迎任何想法或建議。謝謝。

回答

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; 
     [email protected][package].ProperPopupPanel::touchHandler = function(event) { 
      [email protected][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", 
      [email protected][package].ProperPopupPanel::touchHandler, 
      true 
     ); 
     $doc.addEventListener(
      "MozTouchDown", 
      [email protected][package].ProperPopupPanel::touchHandler, 
      true 
     ); 
    }-*/; 


    /** 
    * Remove the touch listeners 
    */ 
    protected native void removeTouchListener() /*-{ 
     $doc.removeEventListener(
      "touchstart", 
      [email protected][package].ProperPopupPanel::touchHandler, 
      true 
     ); 
     $doc.removeEventListener(
      "MozTouchDown", 
      [email protected][package].ProperPopupPanel::touchHandler, 
      true 
     ); 
    }-*/; 


}