我的应用程序中有一个显示 DialogFragment
的 Fragment
。
在该片段中,我有一个关闭对话框的按钮。但是当我显示 DialogFragment 时,触摸对话框外部无效,并且我无法点击对话框片段外部的按钮。
如何允许对 DialogFragment 外部的触摸?
我的应用程序中有一个显示 DialogFragment
的 Fragment
。
在该片段中,我有一个关闭对话框的按钮。但是当我显示 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;
}
});
}
@yaniv已经提供了答案。但是如果您想要,这里有一个片段,您可以在不需要将Runnable
发布到根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;
}
我已经在编程方面测试了被接受的答案(Yaniv的答案)。
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个华为手机以及运行从Android 5到10的约20个三星手机上,下面的方法都能正常工作。
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;
}
根据我所做的调查,我认为这应该是被接受的答案:
@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;
}
即将设置标志移到onCreateDialog()的末尾,并添加setCancelOnTouchOutside(false)。
接受的答案在运行Android 9和10的三星手机上不起作用(很可能也包括11)。看起来在这些系统上,三星已经改变了一些东西,使得只有在非常早期设置这些标志才能起作用。
以上内容适用于所有地方,包括Google模拟器、LG Nexus 5X、HTC Desire 12、Google Pixel 6、几款华为手机以及我测试过的所有(约20个)三星手机。
好的,让我们具体说明。 如果你想使用外部视图,那么你不应该使用对话框片段(Dialog Fragment),而应该像这样使用片段(Fragment)。
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,这样它看起来就像对话框,并且默认情况下它位于屏幕顶部。
更多详情请访问此处
应该接受@Alexandre Bodi的答案。
在我的情况下,每次打开片段时Runnable()会使整个屏幕闪烁。 如果有人需要一个没有闪烁的干净的Kotlin方法,这里就是:
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val dialog = super.onCreateDialog(savedInstanceState)
dialog.window?.addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL)
dialog.window?.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND)
return dialog
}