如何在对话框外点击以关闭对话框?

177

我已经为我的应用程序实现了一个自定义对话框。我希望在用户单击对话框外部时,对话框会被关闭。 我需要做什么才能实现这一功能?

14个回答

385
你可以使用dialog.setCanceledOnTouchOutside(true);来实现在对话框外部触摸时关闭对话框。像这样:
  Dialog dialog = new Dialog(context)
  dialog.setCanceledOnTouchOutside(true);

如果你的对话框不是模态的,则:

1 - 为你的对话框窗口属性设置标志FLAG_NOT_TOUCH_MODAL

Window window = this.getWindow();
window.setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);

2 - 添加另一个标志到Windows属性,FLAG_WATCH_OUTSIDE_TOUCH - 这个标志是为了让对话框可以接收其可见区域外的触摸事件。

3 - 重写对话框的onTouchEvent()方法并检查动作类型。如果动作类型是'MotionEvent.ACTION_OUTSIDE',表示用户正在对话框区域外进行交互。在这种情况下,您可以关闭对话框或决定您想要执行什么操作。 view plainprint?

public boolean onTouchEvent(MotionEvent event)  
{  

       if(event.getAction() == MotionEvent.ACTION_OUTSIDE){  
        System.out.println("TOuch outside the dialog ******************** ");  
               this.dismiss();  
       }  
       return false;  
}  

如需了解更多信息,请查看如何基于触点取消自定义对话框?如何在点击对话框区域外部时取消非模态对话框


9
除了底下的活动也对触摸事件做出反应之外,这很好用。有没有什么办法可以防止这种情况发生? - howettl
使用非自定义对话框,是否可以将“on-touch-outside”事件传播到下面的活动? - j.c
2
@howettl 我已经在我的解决方案中解决了你的问题,我在下面发布了,我不需要设置任何窗口标志。 - Roman Nazarevych
当对话框被关闭时,我会给它一个向下滑动的动画,但是当我打开对话框并且没有关闭对话框时,我按下手机上的最小化按钮,此时我的对话框会自动关闭,并带有向下滑动的一些效果,这不好,所以如何防止在那个时候关闭对话框。提前致谢。 - Ganpat Kaliya
在提出Flag watch外部触摸的问题上,您给出了很好的答案。 - user9599745
显示剩余2条评论

22

只需要简单地使用

dialog.setCanceledOnTouchOutside(true);

4
我知道这应该是正确的答案,但对我不起作用,我不知道为什么。 - IgniteCoders

17
您可以使用此 onTouchEvent 的实现。它可以防止在触摸事件下方对活动做出反应(如 howettl 所提到的)。
@Override
public boolean onTouchEvent ( MotionEvent event ) {
  // I only care if the event is an UP action
  if ( event.getAction () == MotionEvent.ACTION_UP ) {
    // create a rect for storing the window rect
    Rect r = new Rect ( 0, 0, 0, 0 );
    // retrieve the windows rect
    this.getWindow ().getDecorView ().getHitRect ( r );
    // check if the event position is inside the window rect
    boolean intersects = r.contains ( (int) event.getX (), (int) event.getY () );
    // if the event is not inside then we can close the activity
    if ( !intersects ) {
      // close the activity
      this.finish ();
      // notify that we consumed this event
      return true;
    }
  }
  // let the system handle the event
  return super.onTouchEvent ( event );
}

来源: http://blog.twimager.com/2010/08/closing-activity-by-touching-outside.html


9

如果您正在使用在样式xml中定义的主题自定义对话框,请在您的主题中放置此行:

<item name="android:windowCloseOnTouchOutside">true</item>

这在我的三星Galaxy Tab 2 WiFi上不起作用。dialog.setCanceledOnTouchOutside(true);非常有效。 - doplumi

9
dialog.setCanceledOnTouchOutside(true); 

在触摸对话框外部时关闭它。

如果您不想在触摸对话框外部关闭它,请使用以下代码:

dialog.setCanceledOnTouchOutside(false);

9

如果您有以下代码,请删除它,这个方法应该完全避免获取灰色区域下面的点击事件。

window.setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);

将这个放在你的活动创建中。
getWindow().setFlags(LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH, LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH);

然后用这个覆盖触摸事件。
@Override
public boolean onTouchEvent(MotionEvent ev)
{
    if(MotionEvent.ACTION_DOWN == ev.getAction())
    {
        Rect dialogBounds = new Rect();
        getWindow().getDecorView().getHitRect(dialogBounds);
        if (!dialogBounds.contains((int) ev.getX(), (int) ev.getY())) {
            // You have clicked the grey area
            displayYourDialog();
            return false; // stop activity closing
        }
    }

    // Touch events inside are fine.
    return super.onTouchEvent(ev);
}

7
你可以尝试这个方法:-
AlterDialog alterdialog;
alertDialog.setCanceledOnTouchOutside(true);

或者

alertDialog.setCancelable(true);

如果你拥有一个AlertDialog.Builder,那么你可以尝试以下方法:

alertDialogBuilder.setCancelable(true);

5

这段代码用于在用户点击对话框时隐藏键盘输入法,在用户点击对话框外部时,同时关闭软键盘输入法和对话框。

dialog = new Dialog(act) {
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // Tap anywhere to close dialog.
        Rect dialogBounds = new Rect();
        getWindow().getDecorView().getHitRect(dialogBounds);
        if (!dialogBounds.contains((int) event.getX(),
                (int) event.getY())) {
            // You have clicked the grey area
            InputMethodManager inputMethodManager = (InputMethodManager) act
                    .getSystemService(act.INPUT_METHOD_SERVICE);
            inputMethodManager.hideSoftInputFromWindow(dialog
                    .getCurrentFocus().getWindowToken(), 0);
            dialog.dismiss();
            // stop activity closing
        } else {
            InputMethodManager inputMethodManager = (InputMethodManager) act
                    .getSystemService(act.INPUT_METHOD_SERVICE);
            inputMethodManager.hideSoftInputFromWindow(dialog
                    .getCurrentFocus().getWindowToken(), 0);
        }

        return true;
    }
};

3
另一种解决方案,这段代码摘自于Window的安卓源代码。 你只需将这两个方法添加到对话框源代码中即可。
@Override
public boolean onTouchEvent(MotionEvent event) {        
    if (isShowing() && (event.getAction() == MotionEvent.ACTION_DOWN
            && isOutOfBounds(getContext(), event) && getWindow().peekDecorView() != null)) {
        hide();
    }
    return false;
}

private boolean isOutOfBounds(Context context, MotionEvent event) {
    final int x = (int) event.getX();
    final int y = (int) event.getY();
    final int slop = ViewConfiguration.get(context).getScaledWindowTouchSlop();
    final View decorView = getWindow().getDecorView();
    return (x < -slop) || (y < -slop)
            || (x > (decorView.getWidth()+slop))
            || (y > (decorView.getHeight()+slop));
}

这个解决方案没有这个问题:

这个方法很好,但是底层的活动也会对触摸事件做出反应。有什么办法可以防止这种情况发生吗?- howettl


如果您不希望其他窗口接收事件,那么您能否将对话框设置为触摸模态? - user9599745

3

以下方法对我有效:

myDialog.setCanceledOnTouchOutside(true);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接