在使用DialogFragment时有需求要DialogFragment在界面内一直展示,不能随返回键关闭,这时候就需要处理DialogFragment的返回事件: 在DialogFragment中使用setCancelable(false) 可以让DialogFragment不随返回键关闭,但这样处理又会导致返回事件被Dialog消化,无法传递到Activity,Activity无法关闭。
解决方法:
public void setCancelable(boolean cancelable) {
mCancelable = cancelable;
if (mDialog != null) mDialog.setCancelable(cancelable);
}
这个是调用的DialogFragment中setCancelable方法,可以看到它里面也是对内部Dialog进行操作的,再看下Dialog内部怎么处理的
public boolean onKeyDown(int keyCode, @NonNull KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_ESCAPE) {
event.startTracking();
return true;
}
return false;
}
public boolean onKeyUp(int keyCode, @NonNull KeyEvent event) {
if ((keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_ESCAPE)
&& event.isTracking()
&& !event.isCanceled()) {
onBackPressed();
return true;
}
return false;
}
public void onBackPressed() {
if (mCancelable) {
cancel();
}
}
重点是这几个方法,Dialog会在按下物理键的时候在onKeyDown中拦截返回事件,抬起时在onKeyUp方法中将事件传给onBackPressed处理
那就咱们就可以写一个Dialog子类,在子类中重写onKeyDown方法,拦截返回事件交给外部Activity处理
inner class MyDialog(mActivity: Activity, themeResId: Int) :Dialog(mActivity, themeResId) {
init {
setCanceledOnTouchOutside(false)
}
override fun onKeyDown(keyCode : Int , event : KeyEvent) : Boolean {
if (keyCode == KeyEvent.KEYCODE_BACK) {
(mActivity as MyActivity).onKeyDown(keyCode , event)
return true
}
return super.onKeyDown(keyCode , event)
}
}
在DialogFragment中重写onCreateDialog方法
override fun onCreateDialog(savedInstanceState : Bundle?) : Dialog {
return MyDialog(mActivity, theme)
}
这样就完美解决这个问题了!!!