GWT移动/触摸屏设备-启用玻璃后自动隐藏PopupPanel可以在触摸玻璃时触发触摸/单击底层小部件

问题描述

我正在尝试使用启用了玻璃和自动隐藏功能的GWT PopupPanel(或DialogBox)在移动设备上创建上下文操作菜单,但是当用户关闭操作菜单弹出窗口时(通过在玻璃上点击),我遇到了问题弹出式窗口中的内容,在内容之外触发自动隐藏):当关闭弹出式窗口时,基础小部件(在玻璃下面)也将接收tap事件。例如,如果在该位置有一个打开新视图/窗口的按钮,则单击该按钮并执行其单击处理程序。

我的代码

public void onModuleLoad() {
    Button button = new Button("Test");
    button.addClickHandler(cl -> {
        
        Label lb = new Label("This is the content");
        lb.getElement().getStyle().setBackgroundColor("#fff");
        lb.setSize("200px","80px");

        
        DialogBox pop = new DialogBox();
        pop.setAutoHideEnabled(true);
        pop.setGlassEnabled(true);
        pop.setWidget(lb);
        pop.center();
                    
    });
    
    Button buttonBehindGlass = new Button("Test over");
    buttonBehindGlass.addClickHandler(cl -> {           
        Window.alert("Action 2");           
    }); 
    
    RootPanel.get().add(button);
    RootPanel.get().add(buttonBehindGlass);
}

在此示例中,如果您打开弹出窗口,然后在玻璃上的“ buttonBehindGlass”小部件上方单击/轻击内容,您会注意到弹出窗口关闭并且同时单击了“ buttonBehindGlass”

有什么办法可以避免这种情况?

我在启用了响应/触摸模式的Android和Chrome开发工具上进行了测试。这个问题不会出现在台式机上,一切都很好。

解决方法

创建您自己的对话框,基于 GWT

public class DialogBoxExtended extends DialogBox {

    @Override
    protected void onPreviewNativeEvent(NativePreviewEvent event) {
        super.onPreviewNativeEvent(event);

        // check if the event does not target the popup
        Event nativeEvent = Event.as(event.getNativeEvent());
        if (!eventTargetsPopup(nativeEvent)) {
            // on click,touch end,etc. close the dialog box
            switch (event.getTypeInt()) {
            case Event.ONMOUSEDOWN:
            case Event.ONCLICK:
            case Event.ONTOUCHEND:
                hide();
                break;
            }
        }
    }

    /**
     * Does the event target this popup?
     *
     * @param event the native event
     * @return true if the event targets the popup
     */
    private boolean eventTargetsPopup(NativeEvent event) {
        EventTarget target = event.getEventTarget();
        if (Element.is(target)) {
            return getElement().isOrHasChild(Element.as(target));
        }
        return false;
    }
}

禁用自动隐藏使用您创建的对话框

public void onModuleLoad() {
    Button button = new Button("Test");
    button.addClickHandler(cl -> {
        
        Label lb = new Label("This is the content");
        lb.getElement().getStyle().setBackgroundColor("#fff");
        lb.setSize("200px","80px");    
        
        DialogBox pop = new DialogBoxExtended();
        pop.setAutoHideEnabled(false);
        pop.setGlassEnabled(true);
        pop.setWidget(lb);
        pop.center();
                    
    });
    
    Button buttonBehindGlass = new Button("Test over");
    buttonBehindGlass.addClickHandler(cl -> {           
        Window.alert("Action 2");           
    }); 
    
    RootPanel.get().add(button);
    RootPanel.get().add(buttonBehindGlass);
}

它现在按预期工作。

启用自动隐藏后,事件会被处理但留给其他处理程序使用 - 这就是事件到达底层按钮的原因。在桌面上,这不是问题,因为正在考虑 Event.ONMOUSEUP,但在移动/触摸模式下,Event.ONTOUCHEND 被触发。