300字范文,内容丰富有趣,生活中的好帮手!
300字范文 > DialogFragment自动弹出软键盘 消失时关闭软键盘

DialogFragment自动弹出软键盘 消失时关闭软键盘

时间:2022-03-25 16:18:46

相关推荐

DialogFragment自动弹出软键盘 消失时关闭软键盘

目录

弹出和关闭软键盘在DialogFragment显示时弹出软键盘在DialogFragment消失时关闭软键盘1.用户手动调用DialogFragment.dismiss()2.用户点击空白处关闭dialog重写onDismiss(dialog: DialogInterface)自定义Dialog在dismiss之前通知 DialogFragment 关闭软键盘

弹出和关闭软键盘

弹出软键盘

private val imm: InputMethodManager? by lazy {activity?.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager? }private fun showSoftInput() {imm?.let {binding.apply {etChat.requestFocus()it.showSoftInput(etChat, InputMethodManager.SHOW_FORCED)}}}

关闭软键盘

private fun hideSoftInput() {imm?.hideSoftInputFromWindow(binding.etChat.windowToken, 0)}

在DialogFragment显示时弹出软键盘

在DialogFragment显示时有两种方式弹出软键盘:

1、在onViewCreated中发送一个延时任务

etChat.postDelayed({showSoftInput() }, 200)

注意:如果直接调用显示键盘不会起作用,因为这个时候view没有显示出来

2、设置dialog的style属性android:windowSoftInputMode

<style name="live_editTextDialogStyle" parent="@android:style/Theme.Dialog"><!-- 背景透明 --><item name="android:windowBackground">@android:color/transparent</item><item name="android:windowContentOverlay">@null</item><!-- 浮于Activity之上 --><item name="android:windowIsFloating">true</item><!-- 边框 --><item name="android:windowFrame">@null</item><!-- Dialog以外的区域模糊效果 --><item name="android:backgroundDimEnabled">false</item><!-- 无标题 --><item name="android:windowNoTitle">true</item><!-- 半透明 --><item name="android:windowIsTranslucent">true</item><!-- 显示软键盘 --><item name="android:windowSoftInputMode">stateAlwaysVisible</item></style>

在DialogFragment消失时关闭软键盘

dialog关闭分为几种情况,处理方式不一样:

1.用户手动调用DialogFragment.dismiss()

这时可以重写dismiss方法,在调用之前关闭软键盘。

override fun dismiss() {hideSoftInput()super.dismiss()}

2.用户点击空白处关闭dialog

DialogFragment本身没有监听关闭之前的方法,只有两个相关方法onCancel(dialog: DialogInterface)和onDismiss(dialog: DialogInterface)

重写onCancel(dialog: DialogInterface)

override fun onCancel(dialog: DialogInterface) {hideSoftInput()super.onCancel(dialog)}

当这样处理时发现软键盘没有关闭,可以看下流程:

看看InputMethodManager的hideSoftInputFromWindow方法

public boolean hideSoftInputFromWindow(IBinder windowToken, int flags,ResultReceiver resultReceiver) {checkFocus();synchronized (mH) {if (mServedView == null || mServedView.getWindowToken() != windowToken) {return false;}try {return mService.hideSoftInput(mClient, flags, resultReceiver);} catch (RemoteException e) {throw e.rethrowFromSystemServer();}}}

可以看到关闭软键盘的代码为mService.hideSoftInput

断点发现当在onCancel中关闭软键盘时 mServedView为null,所以走不到关闭代码,看一下mServedView在哪赋值为null的

void finishInputLocked() {mNextServedView = null;if (mServedView != null) {if (DEBUG) Log.v(TAG, "FINISH INPUT: mServedView=" + dumpViewInfo(mServedView));if (mCurrentTextBoxAttribute != null) {try {mService.finishInput(mClient);} catch (RemoteException e) {throw e.rethrowFromSystemServer();}}mServedView = null;mCompletions = null;mServedConnecting = false;clearConnectionLocked();}}

finishInputLocked调用有两处地方

private boolean checkFocusNoStartInput(boolean forceNewFocus) {// 已省略其余代码if (mNextServedView == null) {finishInputLocked();// 此方法会调用 mService.hideSoftInput,所以可以排除closeCurrentInput();return false;}return true;}public void windowDismissed(IBinder appWindowToken) {checkFocus();synchronized (mH) {if (mServedView != null &&mServedView.getWindowToken() == appWindowToken) {finishInputLocked();}}}

所以可以判断当回调到onCancel的时候,windowDismissed方法已经调用,所以无法关闭软键盘。此方式排除,再来看看onDismiss方法

重写onDismiss(dialog: DialogInterface)

override fun onDismiss(dialog: DialogInterface) {hideSoftInput()super.onDismiss(dialog)}

在onDismiss调用时发现 hideSoftInputFromWindow()中的 mServedView不为null,但是 windowToken == null,看一下这个参数的获取

imm?.hideSoftInputFromWindow(binding.etChat.windowToken, 0)// View.java ->public IBinder getWindowToken() {return mAttachInfo != null ? mAttachInfo.mWindowToken : null;}

mAttachInfo会在 dispatchDetachedFromWindow()中置为null。因为我们传入的etchat所在窗口已经关闭,所以获取的 windowToken为null。

再来看 mServedView不为null的值,发现是我 DialogFragment 依附的 activity的布局控件,可以理解为当前获取焦点的控件,因此可以传入activity中当前焦点所在的view试试,代码改为:

override fun onDismiss(dialog: DialogInterface) {val view = activity?.window?.currentFocusview?.let {imm?.hideSoftInputFromWindow(it.windowToken, 0) }super.onDismiss(dialog)}

运行后软键盘正常关闭,OK,问题解决。

本以为问题已解决,但是在操作的时候发现会有偶发的关闭失效,发现又是 mServedView == null,原因未知,没办法,这种方式不够保险。

自定义Dialog在dismiss之前通知 DialogFragment 关闭软键盘

转变思路,既然在 DialogFragment 中无法提前监听dialog关闭,那就自定义Dialog重写dismiss方法,在Dialog关闭之前告知 DialogFragment 关闭软键盘

class EditDialog(context: Context?, theme: Int) : Dialog(context, theme) {override fun dismiss() {onDismissListener?.invoke()super.dismiss()}var onDismissListener: (() -> Unit)? = null}override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {val dialog = EditDialog(context, R.style.live_editTextDialogStyle)dialog.onDismissListener = {hideSoftInput() }return dialog}

在DialogFragment的onCreateDialog中创建自定义的Dialog,设置关闭回调。

最后,还有一种方式就是使用全屏dialog,在原先空白区域加一个透明的View,设置view的点击事件去关闭软键盘和弹窗,这样就避免了点击空白处关闭的问题。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。