允许外部触摸DialogFragment

时间:2013-03-13 10:21:11

标签: android android-dialogfragment

我的应用中有Fragment,显示DialogFragment 我在片段中有一个关闭对话框的按钮。但是当我显示dialogFragment时,对话框外部的触摸什么都不做,我无法点击对话框片段外的按钮。

如何为DialogFragment提供外部触摸?

8 个答案:

答案 0 :(得分:18)

为了做到这一点,应该打开允许外部触摸的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);
}

答案 1 :(得分:4)

这是更通用的标志,允许任何动作不仅触及动作

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

答案 2 :(得分:1)

我找到了替代方法来处理外面的触摸。请检查以下代码示例,这肯定有用,

@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()视为非null值,但是getDialog()。dismiss()无效。此外,标记为右上方的解决方案在我的情况下也不起作用。所以,我采用了这种方法。

答案 3 :(得分:1)

根据我上面的小调查,我真的认为这应该是公认的答案:

  @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)的Samsung手机。看起来像在这些系统上,三星已经进行了一些更改,使得设置这些标志只能在设置得很早的情况下起作用。

以上方法适用于任何地方,包括Google模拟器,LG Nexus 5X,HTC Desire 12,Google Pixel 6,一些华为手机以及我测试过的所有(约20款)三星手机。

答案 4 :(得分:0)

您需要根据自己的需要设置合适的款式。您可以在official docs中阅读有关FragmentDialogs样式的更多信息。

我相信你可以使用以下风格:

  • STYLE_NO_FRAME

答案 5 :(得分:0)

嗯,让我们具体一点。 如果你想使用外部视图,那么你不应该使用对话框片段,而是像这样使用片段。

 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,默认情况下它位于屏幕顶部。

有关详细信息,请访问here

答案 6 :(得分:0)

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

答案 7 :(得分:-1)

我已经测试了接受的(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之外的Button时,根本不会调用其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;
    }