【问题标题】:Android hide keyboad and dismiss bottomsheetfragment when back pressed回按时Android隐藏键盘并关闭底部片断
【发布时间】:2021-06-29 16:09:06
【问题描述】:

我遇到了隐藏bottomsheetfragment 和一键后退键盘的问题。当前的实现要求用户单击返回两次以关闭键盘和底页。

我实现了setOnKeyListener,但第一次后退点击隐藏键盘,第二次点击触发后退事件

Link to video

对话框样式

 <style name="BottomSheetDialog" parent="Theme.Design.Light.BottomSheetDialog">
        <item name="android:windowIsFloating">false</item>
        <item name="android:statusBarColor">@android:color/transparent</item>
        <item name="android:windowSoftInputMode">adjustResize</item>
    </style>
class CommentInputFragment : BottomSheetDialogFragment() {

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
     setStyle(DialogFragment.STYLE_NORMAL, R.style.BottomSheetDialog);


}

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                          savedInstanceState: Bundle?): View? {
    // Inflate the layout for this fragment
    var view= inflater.inflate(R.layout.fragment_comment_input, container, false)
    return view;
}

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

    return dialog

}

override fun onResume() {
    super.onResume()

    dialog?.setOnKeyListener(object: DialogInterface.OnKeyListener
    {
        override fun onKey(p0: DialogInterface?, keyCode: Int, p2: KeyEvent?): Boolean {
            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;
        }
    })
}

override fun onActivityCreated(savedInstanceState: Bundle?) {
    super.onActivityCreated(savedInstanceState)
    et_add_comment.requestFocus();
}


}

【问题讨论】:

  • 您在fragment_comment_input 中使用哪种根布局类型?是LinearLayout吗?
  • 根是FrameLayout

标签: android kotlin android-softkeyboard bottomsheetdialogfragment onkeylistener


【解决方案1】:

隐藏键盘并关闭对话框。

 override fun onKey(p0: DialogInterface?, keyCode: Int, event: KeyEvent?): Boolean {
        if ((keyCode ==  android.view.KeyEvent.KEYCODE_BACK &&  event.getAction()== KeyEvent.ACTION_DOWN))
        {
            // To dismiss the fragment when the back-button is pressed.
            val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as? 
           InputMethodManager
           imm?.hideSoftInputFromWindow(view.windowToken, 0)
            dismiss();
            
            return true;
        }

【讨论】:

  • 同样的东西需要点击后面两次隐藏键盘和底页
  • 您是否添加了“event.getAction()== KeyEvent.ACTION_DOWN”? @AhmadNasser
  • 如果您在 onKey 覆盖中使用 return false 而不是 return true 怎么办?
  • @androidLearner 是的,我没有影响
  • @CSmith 我改成 false 没有影响
【解决方案2】:

问题:

如果您注意到返回箭头指向底部(在最近的设备中)而不是左侧,则在这种情况下,对话框不会拦截返回,因为它是由软键盘触发的。所以不会触发dialog?.setOnKeyListener的回调。

所以,你需要通过一些键盘监听器来拦截按键事件;好吧,对于herethere 等许多帖子来说,这是一个挑战,每个解决方案都可以在特定情况下工作。

解决方案

当调用dispatchKeyEventPreIme() 时,我们将向BottomSheetFragment 布局(R.layout.fragment_comment_input) 的根ViewGroup 注册一个侦听器。这会为附加到此布局的关键事件调用。

创建监听器:

interface OnBackPressListener {
    fun onBackPressed(event: KeyEvent)
}

所以,因为根是FrameLayout,然后自定义它:

class DispatchKeyFrameLayout @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : FrameLayout(context, attrs, defStyleAttr) {

    private var listener: OnBackPressListener? = null

    fun setOnBackPressListener (listener: OnBackPressListener) {
        this.listener = listener
    }

    override fun dispatchKeyEventPreIme(event: KeyEvent): Boolean {
        // Trigger the listener callback
        listener?.onBackPressed(event)
        return super.dispatchKeyEventPreIme(event)
    }
}

并将其用作R.layout.fragment_comment_input中的根布局:

<com.example.kotlintest.DispatchKeyFrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/root_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

<!--Other views-->

</com.example.kotlintest.DispatchKeyFrameLayout>

然后在BottomSheetFragment onResume() 中设置监听器以关闭对话框。

override fun onResume() {
    super.onResume()

    layout.setOnBackPressListener(object : OnBackPressListener{
        override fun onBackPressed(event: KeyEvent) {
            if (event.keyCode == android.view.KeyEvent.KEYCODE_BACK)
                dismiss()
        }
    })
}

现在您可以安全地删除dialog?.setOnKeyListener

预览:

【讨论】:

    【解决方案3】:

    我通过使用自定义 EditText 解决了这个问题

    public class CustomEditText extends EditText {
    
    public CustomEditText(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    
    @Override
    public boolean onKeyPreIme(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            // User has pressed Back key. So hide the keyboard
            InputMethodManager mgr = (InputMethodManager)
    
                    getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
            mgr.hideSoftInputFromWindow(this.getWindowToken(), 0);
        }
        return false;
    }
    }
    

    【讨论】:

    • 如何在xml中调用这个组件? ,我试试这个但得到错误无法解析类:(
    【解决方案4】:
    override fun onBackPressed() {
        super.onBackPressed()
        val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as? 
           InputMethodManager
        imm?.hideSoftInputFromWindow(view.windowToken, 0)
        dismiss();
     }
    

    【讨论】:

    • BottomSheetDialogFragment 中没有 onBackPressed
    猜你喜欢
    • 1970-01-01
    • 2017-08-24
    • 1970-01-01
    • 2013-12-09
    • 1970-01-01
    • 1970-01-01
    • 2014-12-26
    • 2015-09-04
    • 2017-06-07
    相关资源
    最近更新 更多