web-dev-qa-db-ja.com

BottomSheetDialogFragment-ユーザーイベントによる却下をリッスンします

BottomSheetDialogFragmentの最終解雇を聞くにはどうすればよいですか?最終解雇時にのみユーザーの変更を保存したい...

私は次のことを試しました:

方法1

これは、ダイアログが下にスワイプして閉じられた場合にのみ発生します(バックプレスまたは外側のタッチではありません)。

@Override
public Dialog onCreateDialog(Bundle savedInstanceState)
{
    Dialog d = super.onCreateDialog(savedInstanceState);
    d.setOnShowListener(new DialogInterface.OnShowListener() {
        @Override
        public void onShow(DialogInterface dialog) {

            BottomSheetDialog d = (BottomSheetDialog) dialog;   
            FrameLayout bottomSheet = (FrameLayout) dialog.findViewById(Android.support.design.R.id.design_bottom_sheet);

            BottomSheetBehavior behaviour = BottomSheetBehavior.from(bottomSheet);
            behaviour.setState(BottomSheetBehavior.STATE_EXPANDED);
            behaviour.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
                @Override
                public void onStateChanged(@NonNull View bottomSheet, int newState) {
                    if (newState == BottomSheetBehavior.STATE_HIDDEN)
                    {
                        // Bottom Sheet was dismissed by user! But this is only fired, if dialog is swiped down! Not if touch outside dismissed the dialog or the back button
                        Toast.makeText(MainApp.get(), "HIDDEN", Toast.LENGTH_SHORT).show();
                        dismiss();
                    }
                }

                @Override
                public void onSlide(@NonNull View bottomSheet, float slideOffset) {

                }
            });
        }
    });
    return d;
}

方法2

これにより、最終的な解雇と、画面の回転やアクティビティのレクリエーションからの解雇を区別できません...

 @Override
public void onDismiss(DialogInterface dialog)
{
    super.onDismiss(dialog);
    // this works fine but fires one time too often for my use case, it fires on screen rotation as well, although this is a temporarily dismiss only
    Toast.makeText(MainApp.get(), "DISMISSED", Toast.LENGTH_SHORT).show();
}

質問

ユーザーがダイアログを終了したことを示すイベントを聞くにはどうすればよいですか?

16
prom85

SOに関する同様の質問はすべて、onDismissの使用を推奨していますが、以下が正しい解決策だと思います。

@Override
public void onCancel(DialogInterface dialog)
{
    super.onCancel(dialog);
    Toast.makeText(MainApp.get(), "CANCEL", Toast.LENGTH_SHORT).show();
}

これは次の場合に起動します:

* the user presses back
* the user presses outside of the dialog

これは起動しません:

* on screen rotation and activity recreation

ソリューション

onCancelBottomSheetBehavior.BottomSheetCallback.onStateChangedを次のように組み合わせます:

public class Dailog extends BottomSheetDialogFragment
{
    @Override
    public void onCancel(DialogInterface dialog)
    {
        super.onCancel(dialog);
        handleUserExit();
    }

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState)
    {
        Dialog d = super.onCreateDialog(savedInstanceState);
        d.setOnShowListener(new DialogInterface.OnShowListener() {
            @Override
            public void onShow(DialogInterface dialog) {
                BottomSheetDialog d = (BottomSheetDialog) dialog;
                FrameLayout bottomSheet = (FrameLayout) d.findViewById(Android.support.design.R.id.design_bottom_sheet);
                BottomSheetBehavior behaviour = BottomSheetBehavior.from(bottomSheet);
                behaviour.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
                    @Override
                    public void onStateChanged(@NonNull View bottomSheet, int newState) {
                        if (newState == BottomSheetBehavior.STATE_HIDDEN)
                        {
                            handleUserExit();
                            dismiss();
                        }
                    }

                    @Override
                    public void onSlide(@NonNull View bottomSheet, float slideOffset) {

                    }
                });
            }
        });
        return d;
    }

    private void handleUserExit()
    {
        Toast.makeText(MainApp.get(), "TODO - SAVE data or similar", Toast.LENGTH_SHORT).show();
    }
}
34
prom85

私はこの簡単なトリックを使用してこれを達成しました

val bottomSheetDialog = FeedbackFormsFragment.createInstance()
bottomSheetDialog.show((activity as FragmentActivity).supportFragmentManager, BOTTOM_SHEET)


// add some delay to allow the bottom sheet to be visible first so that the dialog is not null

                Handler().postDelayed({
                    bottomSheetDialog.dialog?.setOnDismissListener {

                       // add code here
                    }
                }, 1000)
2
Rashad.Z

@ prom85のメソッドは機能しますが、別のメソッドがあります。ある場合にBottomSheetDialogFragmentを却下し、別の場合には保持したい場合、それは機能しません。すべての場合にダイアログを閉じます。

たとえば、EditTextBottomSheetDialogFragmentの内側にテキストを入力し、ときどき外側をクリックすると、警告なしにダイアログが閉じます。 https://medium.com/@anitas3791/Android-bottomsheetdialog-3871a6e9d538 を試しましたが、動作しますが、別のシナリオで。ダイアログを下にドラッグすると、ダイアログは閉じられます。外部をクリックしても、警告メッセージは表示されず、ダイアログは閉じられません。

そこで、私は https://stackoverflow.com/a/50734566/291414 から@shijoの素晴らしいアドバイスを使用しました。

これらの行をonActivityCreatedメソッド(またはonCreateViewの後の他のライフサイクルメソッド)に追加します。

_@Override 
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    View touchOutsideView = getDialog().getWindow()
        .getDecorView()
        .findViewById(Android.support.design.R.id.touch_outside);
    touchOutsideView.setOnClickListener(yourClickListener);
}
_

私の場合、yourClickListenerでテキストを確認し、アラートを表示するか、ダイアログを閉じます。

_private fun checkAndDismiss() {
    if (newText == oldText) {
        dismissAllowingStateLoss()
    } else {
        showDismissAlert()
    }
}
_

BottomSheetDialogFragmentを作成するとき、 https://stackoverflow.com/a/42679131/291414 のようにsetCancelable(false)を呼び出さないでください。作業。そして、スタイルに_<item name="Android:windowCloseOnTouchOutside">false</item>_を設定したり、onCreateDialogsetCanceledOnTouchOutside(false)を設定したりしないでください。


キャンセル動作をオーバーライドする方法もいくつか試しましたが、成功しませんでした。

_<style name="BottomSheetDialogTheme" parent="Theme.Design.Light.BottomSheetDialog">
    <item name="Android:windowCloseOnTouchOutside">false</item>
</style>

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setStyle(STYLE_NORMAL, R.style.BottomSheetDialogTheme)
}

override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
    val dialog = super.onCreateDialog(savedInstanceState)

    dialog.setOnShowListener {
        val bottomSheet = dialog.findViewById<View>(
            Android.support.design.R.id.design_bottom_sheet) as? FrameLayout
        val behavior = BottomSheetBehavior.from(bottomSheet)
        behavior.state = BottomSheetBehavior.STATE_EXPANDED
        behavior.setBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {
            override fun onSlide(bottomSheet: View, slideOffset: Float) {
            }

            override fun onStateChanged(bottomSheet: View, newState: Int) {
                //showing the different states.
                when (newState) {
                    BottomSheetBehavior.STATE_HIDDEN -> dismiss() //if you want the modal to be dismissed when user drags the bottomsheet down
                    BottomSheetBehavior.STATE_EXPANDED -> {
                    }
                    BottomSheetBehavior.STATE_COLLAPSED -> {
                    }
                    BottomSheetBehavior.STATE_DRAGGING -> {
                    }
                    BottomSheetBehavior.STATE_SETTLING -> {
                    }
                }
            }
        })
        dialog.setOnCancelListener {
            // Doesn't matter what you write here, the dialog will be closed.
        }
        dialog.setOnDismissListener {
            // Doesn't matter what you write here, the dialog will be closed.
        }
    }

    return dialog
}

override fun onCancel(dialog: DialogInterface?) {
    // Doesn't matter what you write here, the dialog will be closed.
    super.onCancel(dialog)
}

override fun onDismiss(dialog: DialogInterface?) {
    // Doesn't matter what you write here, the dialog will be closed.
    super.onDismiss(dialog)
}
_
0
CoolMind