如何在键盘弹出时调整Android Bottom Sheet Dialog布局
我想要实现这样的效果:
- 无键盘时:底部弹窗内容垂直分布,按钮位于弹窗底部
- 弹出键盘时:弹窗内容上移,按钮不被键盘遮挡,保持在可见区域内
我的实现代码如下:
recovery_password_dialog.xml
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout 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:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity" android:id="@+id/parent"> <TextView android:id="@+id/textView6" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="10dp" android:text="Odzyskiwanie hasła" android:textSize="20sp" android:textStyle="bold" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/message" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="10dp" android:text="Wpisz swój email, a my wyślemy wiadomość w celu zresetowania hasła" android:textSize="15sp" android:textStyle="bold" android:textAlignment="center" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toBottomOf="@id/textView6"/> <com.google.android.material.textfield.TextInputLayout android:layout_width="0dp" android:layout_height="wrap_content" android:id="@+id/email_input_layout" android:hint="@string/email" app:endIconMode="clear_text" app:counterMaxLength="64" app:startIconDrawable="@drawable/mail_icon" app:layout_constraintTop_toBottomOf="@id/message" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintVertical_bias="0.1" app:layout_constraintWidth_percent="0.9" style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"> <com.google.android.material.textfield.TextInputEditText android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/email" android:inputType="textEmailAddress"/> </com.google.android.material.textfield.TextInputLayout> <TextView android:id="@+id/invalidEmailText" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/invalid_email" android:textColor="@color/red" android:textStyle="bold" android:visibility="invisible" android:layout_marginTop="5dp" app:layout_constraintTop_toBottomOf="@id/email_input_layout" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.1"/> <Button android:id="@+id/sendEmail" android:layout_width="0dp" android:layout_height="wrap_content" android:background="@drawable/rounding_rect" android:text="@string/send_email" android:textColor="@color/white" android:textSize="16sp" android:textStyle="bold" android:layout_marginBottom="50dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/invalidEmailText" app:layout_constraintVertical_bias="0.0" app:layout_constraintWidth_percent="0.9" /> </androidx.constraintlayout.widget.ConstraintLayout>
LoginFragment.java
var recoverPasswordButton = binding.recoverPassword; recoverPasswordButton.setOnClickListener(v -> { var inflater = LayoutInflater.from(requireContext()); var bottomSheetDialog = new BottomSheetDialog(requireContext(), R.style.BottomSheetDialogTheme); var sheetBinding = RecoveryPasswordDialogBinding.inflate(inflater); bottomSheetDialog.setContentView(sheetBinding.getRoot()); bottomSheetDialog.show(); });
这只是一段仅展示对话框窗口的简单代码,尚未实现任何组件功能。
实际效果:
- 无键盘时:弹窗布局正常显示
- 弹出键盘时:底部的发送按钮被键盘完全遮挡,无法点击
我目前不关注主题和颜色,只关心按钮被键盘遮挡的问题,这不是我想要的效果。我了解到windowSoftInputMode可能有帮助,但我的默认配置已经设置为android:windowSoftInputMode="stateHidden|adjustResize"。也有说法称ScrollView能解决,但实际没有任何变化。
请问有什么方法可以实现示例中的效果?
编辑:添加ScrollView后的代码
<?xml version="1.0" encoding="utf-8"?> <ScrollView 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:layout_width="match_parent" android:layout_height="match_parent" android:fillViewport="true" android:isScrollContainer="true"> <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="wrap_content" tools:context=".MainActivity" android:id="@+id/parent"> <TextView android:id="@+id/textView6" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="10dp" android:text="@string/password_recovery" android:textSize="20sp" android:textStyle="bold" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/message" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="10dp" android:text="Wpisz swój email, a my wyślemy wiadomość w celu zresetowania hasła" android:textSize="15sp" android:textStyle="bold" android:textAlignment="center" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toBottomOf="@id/textView6"/> <com.google.android.material.textfield.TextInputLayout android:layout_width="0dp" android:layout_height="wrap_content" android:id="@+id/email_input_layout" android:hint="@string/email" app:endIconMode="clear_text" app:counterMaxLength="64" app:startIconDrawable="@drawable/mail_icon" app:layout_constraintTop_toBottomOf="@id/message" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintVertical_bias="0.1" app:layout_constraintWidth_percent="0.9" style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"> <com.google.android.material.textfield.TextInputEditText android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/email" android:inputType="textEmailAddress"/> </com.google.android.material.textfield.TextInputLayout> <TextView android:id="@+id/invalidEmailText" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/invalid_email" android:textColor="@color/red" android:textStyle="bold" android:visibility="invisible" android:layout_marginTop="5dp" app:layout_constraintTop_toBottomOf="@id/email_input_layout" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.1"/> <Button android:id="@+id/sendEmail" android:layout_width="0dp" android:layout_height="wrap_content" android:background="@drawable/rounding_rect" android:text="@string/send_email" android:textColor="@color/white" android:textSize="16sp" android:textStyle="bold" android:layout_marginBottom="50dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/invalidEmailText" app:layout_constraintVertical_bias="0.0" app:layout_constraintWidth_percent="0.9" /> </androidx.constraintlayout.widget.ConstraintLayout> </ScrollView>
问题出在BottomSheetDialog本身的窗口配置,即使你在Activity里设置了adjustResize,BottomSheetDialog作为独立窗口,需要单独配置软键盘模式。另外,布局的约束也需要调整来适配滚动容器。
步骤1:给BottomSheetDialog设置软键盘模式
在显示BottomSheetDialog之前,添加以下代码:
bottomSheetDialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
这会让BottomSheetDialog的窗口在键盘弹出时自动调整大小,而不是被遮挡。
步骤2:优化ScrollView内的布局约束
当前的ConstraintLayout高度设为wrap_content,并且按钮绑定到了parent的底部,在ScrollView里这种约束会导致按钮无法跟随窗口上移。修改两点:
- 将ConstraintLayout的
android:layout_height改为match_parent,让它填充ScrollView的高度 - 给按钮添加
app:layout_constraintVertical_bias="1.0",确保它在ConstraintLayout的底部,同时保留layout_marginBottom
修改后的ConstraintLayout部分代码:
<androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity" android:id="@+id/parent"> <!-- 其他控件保持不变 --> <Button android:id="@+id/sendEmail" android:layout_width="0dp" android:layout_height="wrap_content" android:background="@drawable/rounding_rect" android:text="@string/send_email" android:textColor="@color/white" android:textSize="16sp" android:textStyle="bold" android:layout_marginBottom="50dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/invalidEmailText" app:layout_constraintVertical_bias="1.0" app:layout_constraintWidth_percent="0.9" /> </androidx.constraintlayout.widget.ConstraintLayout>
步骤3:检查BottomSheetDialog的主题
确保你的BottomSheetDialogTheme没有覆盖窗口的软键盘相关配置,主题里尽量不要设置windowSoftInputMode,让代码里的设置生效。
最终效果
完成以上修改后,弹出键盘时BottomSheetDialog会自动上移,按钮会保持在可见区域内,同时ScrollView允许你滚动查看上方内容,符合你想要的示例效果。
内容的提问来源于stack exchange,提问作者Shout

