You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在键盘弹出时调整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里这种约束会导致按钮无法跟随窗口上移。修改两点:

  1. 将ConstraintLayout的android:layout_height改为match_parent,让它填充ScrollView的高度
  2. 给按钮添加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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 03:12:02