检测后退按钮但不关闭对话框片段
Posted
技术标签:
【中文标题】检测后退按钮但不关闭对话框片段【英文标题】:Detect back button but don't dismiss dialogfragment 【发布时间】:2014-02-13 23:34:44 【问题描述】:我有一个浮动对话框的对话框片段,其中包括一个特殊键盘,当用户在 EditText 字段内按下时会弹出一个特殊键盘(正常的 IME 停止显示)。
我希望在用户按下后退按钮(就像使用普通 IME 服务一样)时关闭键盘(可见性 = GONE),但对话框保持可见。但是,从我对 SO 和其他地方的相当广泛的阅读中可以看出,似乎没有办法做到这一点。
如果我将对话框设置为不可取消,则 onCancel() 或 onDismiss() 不会通知我,因为对话框不可取消。
如果我将对话框设置为可取消,我会收到通知,但对话框会被关闭。
我无法将 onKeyListener 附加到片段中的对话框,因为它已被系统替换,以便片段可以处理对话框的生命周期。
有没有办法做到这一点?或者是否为了 Fragment 系统的目的而完全隔离了对关键事件的检测?
【问题讨论】:
【参考方案1】:作为胡安·佩德罗·马丁内斯(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 的情况下被调用,这意味着没有任何东西(没有外部点击)可以取消它并关闭它,并且只允许(从对话框本身)返回按钮来关闭它。
甘巴特!
【讨论】:
完美,谢谢,我想在保持返回按钮功能的同时防止意外的外部点击,对我来说,我所要做的就是在 DialogFragment 内的 onCreateView 中的对话框实例上设置取消(false)。 谢谢,这个答案最适合我的情况。【参考方案2】:试试这个然后回来支持我的评论:D
/**
* Callback when Back button is pressed.
* By default it gonna call back press of host activity
*/
protected open fun onBackPressed()
requireActivity().onBackPressed()
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog
return object : BottomSheetDialog(context!!, theme)
override fun onBackPressed()
this@BaseBottomSheetFragment.onBackPressed()
override fun setOnKeyListener(onKeyListener: DialogInterface.OnKeyListener?)
//Do not call super function
//This function do nothing but DON'T REMOVE this.
//Try to set null for onKeyListener is not working.
【讨论】:
【参考方案3】:扩展上面的Juan Pedro Martinez's 答案。我在DialogFragment
上写了一个扩展,可以从onCreate()
设置它会自动设置关键侦听器并根据生命周期将其删除。
fun DialogFragment.setOnBackPressListener(onBackPress: () -> Boolean)
val listener = DialogInterface.OnKeyListener _, keyCode, event ->
if (keyCode == KeyEvent.KEYCODE_BACK && event?.action != KeyEvent.ACTION_DOWN)
onBackPress()
else
false
val observer = object : LifecycleObserver
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
fun onResume()
dialog?.setOnKeyListener(listener)
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
fun onPause()
dialog?.setOnKeyListener(null)
lifecycle.addObserver(observer)
在DialogFragment#onCreate
中的用法
setOnBackPressListener
// handle back press here
true // return true to indicate back press was handled, false if not
【讨论】:
【参考方案4】:AndroidX OnBackPressedDispatcher 也可以是某人的选项
【讨论】:
好像不是这样的:issuetracker.google.com/issues/149173280【参考方案5】:防止取消DialogFragment:
dialog.setCanceledOnTouchOutside(false)
dialog.setCancelable(false)
dialog.setOnKeyListener dialog, keyCode, event ->
keyCode == KeyEvent.KEYCODE_BACK && event.action == KeyEvent.ACTION_UP
【讨论】:
【参考方案6】:使用 Fragment onCancel 覆盖方法。当您按回时调用它。 这是一个示例:
@Override
public void onCancel(DialogInterface dialog)
super.onCancel(dialog);
// Add you codition
【讨论】:
请注意,使用这种方法您无法处理 DialogFragment 是否会被解除。你可以得到通知,它将被解雇 确实@Leo Droidcoder 知道如何在无法关闭对话框片段之前拦截按下的后退按钮吗?【参考方案7】:使用带有 closeActivity 标志的 DialogFragment 的 onDismiss() 回调
private var closeActivity: Boolean = true
override fun onDismiss(dialog: DialogInterface?)
super.onDismiss(dialog)
if (closeActivity)
activity!!.finish()
【讨论】:
【参考方案8】:怎么没有人提出这个建议?
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;
【讨论】:
【参考方案9】:创建对话框时,同时覆盖 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
...
;
【讨论】:
【参考方案10】:我和你有同样的问题,我已经修复了它,将 onKeyListener 附加到对话框片段。
在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
);
您可以发现的问题之一是这段代码将被执行两次:一次是当用户按下返回按钮时,另一次是当他离开按下它时。在这种情况下,您必须按事件过滤:
@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
);
【讨论】:
我没有使用过滤器,而是添加了 getDialog().setOnKeyListener(null) 来阻止第二次调用。【参考方案11】:最好和最干净的方法是在您在 onCreateDialog() 中创建的对话框中覆盖 onBackPressed()。
@Override
public Dialog onCreateDialog(Bundle savedInstanceState)
return new Dialog(getActivity(), getTheme())
@Override
public void onBackPressed()
//do your stuff
;
【讨论】:
我发现的唯一实际工作正常的解决方案。 这在 DialogFragments 中不起作用,因为 DialogFragment 类中没有 onBackPressed()。 DialogFragments 包装一个对话框 - onCreateDialog 创建这个对话框。它适用于 DialogFragments。 我只能确认这是最好和最简单的解决方案。感谢分享这个@Ian Wong 绝对应该是一个公认的答案。迄今为止最原生的解决方案!以上是关于检测后退按钮但不关闭对话框片段的主要内容,如果未能解决你的问题,请参考以下文章