如何通过点击对话框外面的对话框来解除对话框?

我已经为我的应用程序实现了一个自定义对话框。我想实现这一点,当用户点击外部对话框,该对话框将被解散。 我需要做什么?

175783 次浏览

您可以使一个 background占据所有的屏幕大小 transparent和听取 onClick事件的 dismiss它。

您可以使用 dialog.setCanceledOnTouchOutside(true);,它将关闭对话框,如果您触摸外面的对话框。

比如,

  Dialog dialog = new Dialog(context)
dialog.setCanceledOnTouchOutside(true);

或者如果你的对话框没有模型,

1-为对话框的 window 属性设置标志 -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-这个标志用于对话框在其可见区域外接收触摸事件。

重写对话框的 onTouchEvent()并检查操作类型。如果操作类型是 “ MotionEvent.ACTION_OUTSIDE”表示用户在对话框区域之外进行交互。因此,在这种情况下,您可以放弃对话框或决定要执行的操作。 查看原始指纹?

public boolean onTouchEvent(MotionEvent event)
{


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

更多信息请查看 如何取消基于触点的自定义对话框?如何解除您的非模态对话框,当触摸外部对话框区域

您可以使用 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

简单使用

dialog.setCanceledOnTouchOutside(true);

或者,如果您使用在 xml 样式中定义的主题来定制对话框,那么将这一行放在您的主题中:

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

这种方法应该完全避免活动以下的灰色地带检索点击事件。

删除 这一行,如果你有的话:

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

另一种解决方案,该代码取自 Window的 android 源代码 您只需将这两个方法添加到对话框源代码中。

@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

dialog.setCanceledOnTouchOutside(true);

外接触时关闭对话。

如果你不想在室外接触,可以使用下面的代码:

dialog.setCanceledOnTouchOutside(false);

此代码用于当用户单击对话框时隐藏软输入,当用户单击对话框外侧时软输入和对话框都关闭。

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

你可以试试这个:-

AlterDialog alterdialog;
alertDialog.setCanceledOnTouchOutside(true);

或者

alertDialog.setCancelable(true);

如果你有 AlterDialog.Builder,那么你可以试试这个:-

alertDialogBuilder.setCancelable(true);

从您的活动/片段调用 dialog.setCancelable(false);

以下方法对我很有效:

myDialog.setCanceledOnTouchOutside(true);

这是密码

    dialog.getWindow().getDecorView().setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent ev) {


if(MotionEvent.ACTION_DOWN == ev.getAction())
{
Rect dialogBounds = new Rect();
dialog. getWindow().getDecorView().getHitRect(dialogBounds);
if (!dialogBounds.contains((int) ev.getX(), (int) ev.getY())) {
// You have clicked the grey area
UiUtils.hideKeyboard2(getActivity());
return false; // stop activity closing
}
}
getActivity().dispatchTouchEvent(ev);
return false;
}
});

试试这个,你可以把键盘藏起来

我尝试了一些答案,但我仍然面临一个问题,如当我按外面的对话框是隐藏的,但一个模糊的视图正在显示,再次按将进入父活动。但实际上我想在第一次点击后就去参加家长活动。 所以我做的是

dialog.setOnCancelListener(this);

并改变了我的活动以实现 DialogInterface.OnCancelListener

@Override
public void onCancel(DialogInterface dialog) {
finish();
}

然后,成功了。