web-dev-qa-db-ja.com

戻るボタンを検出しますが、ダイアログフラグメントを無視しません

ユーザーがEditTextフィールド内を押すとポップアップする特別なキーボードを含むフローティングダイアログ用のダイアログフラグメントがあります(通常のIMEは表示されません)。

ユーザーが(通常のIMEサービスの場合と同様に)戻るボタンを押したときにキーボードを閉じて(表示= GONE)、ダイアログが表示されたままになるようにします。ただし、SOおよび他の場所でのかなり広範囲にわたる読み取りからわかる限り、これを行う方法はないようです。

ダイアログをキャンセル不可に設定した場合、ダイアログはキャンセルできないため、onCancel()またはonDismiss()から通知されません。

ダイアログをキャンセル可能に設定すると、通知が表示されますが、ダイアログは閉じられます。

フラグメントがダイアログのライフサイクルを処理できるように、システムによって置き換えられるため、フラグメント内のダイアログにonKeyListenerをアタッチできません。

これを行う方法はありますか?または、主要なイベントの検出へのアクセスは、フラグメントシステムの目的のために完全に隔離されていますか?

61
user3227652

最善の方法で最もクリーンな方法は、onCreateDialog()で作成したダイアログでonBackPressed()をオーバーライドすることです。

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    return new Dialog(getActivity(), getTheme()){
        @Override
        public void onBackPressed() {
            //do your stuff
        }
    };
}
138
Ian Wong

私はあなたと同じ問題を抱えていましたが、onKeyListenerをdialogfragmentにアタッチすることで修正しました。

DialogFragmentを拡張するクラスのメソッドonResume()に次のコードを配置します。

    getDialog().setOnKeyListener(new OnKeyListener()
    {
        @Override
        public boolean onKey(Android.content.DialogInterface dialog, int keyCode,Android.view.KeyEvent event) {

            if ((keyCode ==  Android.view.KeyEvent.KEYCODE_BACK))
                {
                     //Hide your keyboard here!!!
                     return true; // pretend we've processed it
                }
            else 
                return false; // pass on to be processed as normal
        }
    });

ここで見つけることができる問題の1つは、このコードが2回実行されることです。1つはユーザーが戻るボタンを押すとき、もう1つはボタンを押して離れるときです。その場合、イベントでフィルタリングする必要があります。

@Override
public void onResume() {
    super.onResume();

    getDialog().setOnKeyListener(new OnKeyListener()
    {
        @Override
        public boolean onKey(Android.content.DialogInterface dialog, int keyCode,
                Android.view.KeyEvent event) {

            if ((keyCode ==  Android.view.KeyEvent.KEYCODE_BACK))
            {
                //This is the filter
                if (event.getAction()!=KeyEvent.ACTION_DOWN)
                        return true;
                else
                {
                    //Hide your keyboard here!!!!!!
                    return true; // pretend we've processed it
                }
            } 
            else 
                return false; // pass on to be processed as normal
        }
    });
}
64

Juan Pedro Martinezの回答の補遺として、このスレッドを見たときに特定の質問(私が持っていた質問)を明確にすると役立つと思いました。

新しいDialogFragmentを作成し、ユーザーがバックボタンを使用してのみキャンセルできるようにしたい場合は、ランダムな画面タッチがフラグメントを時期尚早にキャンセルしないようにします。これが使用するコードです。

DialogFragmentを呼び出すコードでは、キャンセル可能な設定をfalseに設定して、NOTHINGがフラグメントを破棄したり、画面に触れたりしないようにする必要があります。

DialogFragment mDialog= new MyDialogFragment();
mDialog.setCancelable(false);
mDialog.show(getFragmentManager(), "dialog");

次に、DialogFragment(この場合はMyDaialogFragment.Java)内で、onResumeオーバーライドコードを追加して、ダイアログに[戻る]ボタンをリッスンさせます。押されると、dismiss()を実行してフラグメントを閉じます。

@Override
 public void onResume() 
 {
     super.onResume();

     getDialog().setOnKeyListener(new OnKeyListener()
     {
         @Override
         public boolean onKey(Android.content.DialogInterface dialog, 
                              int keyCode,Android.view.KeyEvent event) 
         {
              if ((keyCode ==  Android.view.KeyEvent.KEYCODE_BACK))
              {
                   // To dismiss the fragment when the back-button is pressed.
                   dismiss();
                   return true;
              }
              // Otherwise, do nothing else
              else return false;
         }
   });

これで、ダイアログは "setCancelable"をfalseに設定して呼び出されます。つまり、何も(外部からのクリックは)キャンセルおよびシャットダウンできず、(ダイアログ自体から)戻るボタンのみを閉じることができます。

がんばって!

17
Brandon

Fragment onCancelオーバーライドメソッドを使用します。戻るときに呼び出されます。サンプルは次のとおりです。

@Override
public void onCancel(DialogInterface dialog) {
    super.onCancel(dialog);

    // Add you codition
}
6
Manimaran A

誰もこれを提案していませんか?

public Dialog onCreateDialog(Bundle savedInstanceState) {
  Dialog dialog = super.onCreateDialog(savedInstanceState);

  // Add back button listener
  dialog.setOnKeyListener(new Dialog.OnKeyListener() {
    @Override
    public boolean onKey(DialogInterface dialogInterface, int keyCode, KeyEvent keyEvent) {
      // getAction to make sure this doesn't double fire
      if (keyCode == KeyEvent.KEYCODE_BACK && keyEvent.getAction() == KeyEvent.ACTION_UP) {
        // Your code here
        return true; // Capture onKey
      }
      return false; // Don't capture
    }
  });

  return dialog;
}
6
user6367733
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    Dialog dialog = new Dialog(getActivity(), getTheme()) {
        @Override
        public void onBackPressed() {
            //your code
        }
    };

    return dialog;
}
1

ダイアログを作成するときに、onBackPressedとonTouchEventの両方をオーバーライドします。

        final Dialog dialog = new Dialog(activity) {
            @Override
            public boolean onTouchEvent(final MotionEvent event) {
                //note: all touch events that occur here are outside the dialog, yet their type is just touching-down
                boolean shouldAvoidDismissing = ... ;
                if (shouldAvoidDismissing) 
                    return true;
                return super.onTouchEvent(event);
            }

            @Override
            public void onBackPressed() {
                boolean shouldAvoidDismissing = ... ;
                if (!shouldSwitchToInviteMode)
                    dismiss();
                else
                    ...
            }
        };
0

closeActivityフラグを指定してDialogFragmentのonDismiss()コールバックを使用する

private var closeActivity: Boolean = true    

override fun onDismiss(dialog: DialogInterface?) {
        super.onDismiss(dialog)

        if (closeActivity) {
            activity!!.finish()
        }
    }
0
Vasudev