我的Fragment
应用中有一个显示DialogFragment
.
我在片段中有一个关闭对话框的按钮。但是当我显示 dialogFragment 时,对话框外部的触摸什么也不做,我无法单击对话框片段外部的按钮。
如何允许 DialogFragment 的外部触摸?
我的Fragment
应用中有一个显示DialogFragment
.
我在片段中有一个关闭对话框的按钮。但是当我显示 dialogFragment 时,对话框外部的触摸什么也不做,我无法单击对话框片段外部的按钮。
如何允许 DialogFragment 的外部触摸?
为了做到这一点,Window
应该打开一个允许外部触摸的标志,并且为了美观,应该清除背景暗淡标志。
由于必须在创建对话框后完成,我通过Handler
.
@Override
public void onViewCreated(final View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
// This is done in a post() since the dialog must be drawn before locating.
getView().post(new Runnable() {
@Override
public void run() {
Window dialogWindow = getDialog().getWindow();
// Make the dialog possible to be outside touch
dialogWindow.setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
dialogWindow.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
getView().invalidate();
}
});
}
此时,外部触摸是可能的。
如果我们想让它更好并且没有框架,可以添加以下代码:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Hide title of the dialog
setStyle(STYLE_NO_FRAME, 0);
}
这是更通用的标志,允许任何操作,而不仅仅是触摸操作
window.setFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
我找到了另一种方法来处理外部触摸时的解雇。请检查下面的代码示例,这肯定会起作用,
@Override
public void onStart() {
// mDialogView is member variable
mDialogView = getView();
mDialogView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
float eventX = event.getRawX();
float eventY = event.getRawY();
int location[] = new int[2];
mDialogView.getLocationOnScreen(location);
if (eventX < location[0] || eventX > (location[0] + mDialogView.getWidth()) || eventY < location[1]
|| eventY > location[1] + mDialogView.getHeight()) {
dismiss();
return true;
}
return false;
}
});
}
就我而言,我得到 getDialog() 不是空值,但 getDialog().dismiss() 不起作用。此外,上面标记的解决方案在我的情况下也不起作用。所以,我采用了这种方法。
根据我上面的小调查,我真的认为这应该是公认的答案:
@Override
public Dialog onCreateDialog(Bundle savedInstanceState)
{
FragmentActivity act = getActivity();
AlertDialog.Builder builder = new AlertDialog.Builder(act);
// ... do your stuff here
Dialog dialog = builder.create();
dialog.setCanceledOnTouchOutside(false);
Window window = dialog.getWindow();
if( window!=null )
{
window.setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
}
return dialog;
}
即把flags的设置移到onCreateDialog()的最后,加上setCancelOnTouchOutside(false)。
接受的答案不适用于运行 Android 9 和 10(很可能是 11)的三星手机。看起来在这些系统上,三星已经改变了一些东西,使得设置这些标志只有在很早设置时才有效。
以上适用于任何地方,包括谷歌模拟器、LG Nexus 5X、HTC Desire 12、谷歌 Pixel 6、几部华为手机,以及我测试过的所有(大约 20 部)三星手机。
我已经测试了接受的(Yaniv's)答案
Galaxy Tab A 9.7 Android 7.1.1: ok
Galaxy Tab A 8.0 Android 7 : ok
Galaxy Tab S4 Android 9 : no touch outside DialogFragment
Galaxy S5 Android 6.0.1 : ok
Galaxy Tab S2 Android 7 : ok
Galaxy Tab S3 Android 9 : no touch outside DialogFragment
Galaxy Tab S4 Android 9 : no touch outside DialogFragment
Galaxy Note Edge Android 6.0.1: ok
Galaxy Note4 Android 6.0.1 : ok
它看起来确实不适用于 Android 9。当我说“不起作用”时,我的意思是当我尝试单击 DialogFragment 外部的按钮时,它的 onClick() 方法根本不会被调用。
编辑:根据我的发现(在评论中),我认为以下应该是公认的答案。以下适用于我测试过的所有地方,包括模拟器、Google Pixel 6、LG Nexus 5X、HTC Desire 12、大约 5 部华为手机和大约 20 部运行 Android 5 到 10 的三星手机。
public Dialog onCreateDialog(Bundle savedInstanceState)
{
FragmentActivity act = getActivity();
AlertDialog.Builder builder = new AlertDialog.Builder(act);
// ... do your stuff here....
Dialog dialog = builder.create();
dialog.setCanceledOnTouchOutside(false);
Window window = dialog.getWindow();
if( window!=null )
{
window.setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
}
return dialog;
}
@yaniv 提供了答案。但如果你愿意,这里有一个片段,你可以得到相同的结果,但不需要将 a 发布Runnable
到 root View
:
@NonNull
@Override
public Dialog onCreateDialog(@Nullable final Bundle savedInstanceState) {
final Dialog dialog = super.onCreateDialog(savedInstanceState);
dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
return dialog;
}
好吧,让我们具体一点。如果你想使用外部视图,那么你不应该使用对话框片段,而是像这样使用片段。
FragmentTransaction transaction = fragmentManager.beginTransaction();
// For a little polish, specify a transition animation
transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
// To make it fullscreen, use the 'content' root view as the container
// for the fragment, which is always the root view for the activity
transaction.add(android.R.id.content, newFragment)
.addToBackStack(null).commit();
并制作布局 wrap_content,它显然看起来像 Dialog,默认情况下它被放置在屏幕的顶部。
欲了解更多详情,请访问这里