Android Snackbar位置调整及软键盘遮挡问题求助
问题描述
原本应用使用Toast,但软键盘弹出时会与Toast重叠,导致内容难以分辨。由于Toast的SetView和GetView方法已废弃,转而使用Snackbar实现自定义View,但遇到两个问题:
- Snackbar显示在应用左下角,希望它像Toast一样:在屏幕底部居中显示,且Snackbar底部与屏幕底部留有一定间距;
- Snackbar显示在软键盘后方,希望它显示在软键盘上方,且不想通过隐藏软键盘来实现。
尝试过Stack Overflow上的相关方案,但问题1中编译CoordinatorLayout失败,设置布局边距也无效;问题2的方案同样无法解决问题。
现有代码
res/layout/snackbar.xml
<?xml version="1.0" encoding="utf-8"?> <TextView style="@style/SomeStyle" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/tvSnackbarText" android:layout_width="wrap_content" android:layout_height="wrap_content" tools:text="Snackbar" />
Fragment中的实现代码
private fun showSnackbarMessage(message: String) { val view: View = LayoutInflater .from(context) .inflate(R.layout.snackbar, null) val tvSnackbarText = view.findViewById<TextView>(R.id.tvSnackbarText) tvSnackbarText.text = message tvSnackbarText.gravity = Gravity.CENTER val snackbar = Snackbar.make(requireView(), "", Snackbar.LENGTH_LONG) snackbar.view.setBackgroundResource(R.drawable.rounded_corner_box_grey_stroke); val params = snackbar.view.layoutParams as FrameLayout.LayoutParams params.height = FrameLayout.LayoutParams.WRAP_CONTENT params.width = FrameLayout.LayoutParams.WRAP_CONTENT snackbar.view.layoutParams = params val layout = snackbar.view as Snackbar.SnackbarLayout layout.addView(view) snackbar.show() }
解决方案
问题1:实现Snackbar底部居中+底部间距
无需依赖CoordinatorLayout,直接修改Snackbar的布局参数即可:
- 清空Snackbar默认内容,避免自定义View叠加;
- 设置SnackbarLayout的gravity为底部居中;
- 通过MarginLayoutParams设置底部间距。
修改后的Fragment代码:
private fun showSnackbarMessage(message: String) { val view: View = LayoutInflater .from(context) .inflate(R.layout.snackbar, null) val tvSnackbarText = view.findViewById<TextView>(R.id.tvSnackbarText) tvSnackbarText.text = message tvSnackbarText.gravity = Gravity.CENTER val snackbar = Snackbar.make(requireView(), "", Snackbar.LENGTH_LONG) snackbar.view.setBackgroundResource(R.drawable.rounded_corner_box_grey_stroke) val snackbarLayout = snackbar.view as Snackbar.SnackbarLayout // 清空默认内容,避免残留布局干扰 snackbarLayout.removeAllViews() snackbarLayout.addView(view) // 设置Snackbar整体居中 snackbarLayout.gravity = Gravity.BOTTOM or Gravity.CENTER_HORIZONTAL // 配置布局参数与底部间距 val params = snackbarLayout.layoutParams as ViewGroup.MarginLayoutParams params.width = FrameLayout.LayoutParams.WRAP_CONTENT params.height = FrameLayout.LayoutParams.WRAP_CONTENT // 从dimens中读取底部间距(需先在res/values/dimens.xml定义) params.bottomMargin = resources.getDimensionPixelSize(R.dimen.snackbar_bottom_margin) snackbarLayout.layoutParams = params snackbar.show() }
在res/values/dimens.xml中添加间距配置:
<dimen name="snackbar_bottom_margin">24dp</dimen>
问题2:让Snackbar显示在软键盘上方
通过调整窗口软键盘模式和给Snackbar添加窗口标记实现:
- 设置Activity窗口为
SOFT_INPUT_ADJUST_RESIZE,确保布局随软键盘调整; - 给Snackbar的View添加
FLAG_ALT_FOCUSABLE_IM标记,使其避开软键盘。
补充修改后的完整代码:
private fun showSnackbarMessage(message: String) { // ... 保留问题1中的所有修改代码 ... // 处理软键盘遮挡 val window = requireActivity().window // 让Activity布局随软键盘调整大小 window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE) // 给Snackbar添加标记,使其显示在软键盘上方 val snackbarLayout = snackbar.view as Snackbar.SnackbarLayout snackbarLayout.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION val windowParams = snackbarLayout.layoutParams as WindowManager.LayoutParams windowParams.flags = windowParams.flags or WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM snackbarLayout.layoutParams = windowParams snackbar.show() }
注意:确保Activity的根布局是可调整大小的容器(如ConstraintLayout、LinearLayout),避免固定高度导致布局无法响应软键盘变化。
内容的提问来源于stack exchange,提问作者Mc_Topaz
相关产品推荐
相关产品推荐

