实现弹窗随键盘上移居中

实现弹窗随键盘上移的核心思路

在Android中,可以通过监听键盘的显示和隐藏事件,动态调整弹窗的位置。关键点在于获取键盘高度,并计算剩余屏幕空间以重新定位弹窗。

kotlin 复制代码
// 在Activity或Fragment中设置键盘监听
val rootView = findViewById<View>(android.R.id.content)
rootView.viewTreeObserver.addOnGlobalLayoutListener {
    val rect = Rect()
    rootView.getWindowVisibleDisplayFrame(rect)
    val screenHeight = rootView.rootView.height
    val keyboardHeight = screenHeight - rect.bottom
    if (keyboardHeight > screenHeight * 0.15) {
        // 键盘显示,调整弹窗位置
        adjustDialogPosition(keyboardHeight)
    } else {
        // 键盘隐藏,恢复默认位置
        resetDialogPosition()
    }
}

创建自定义弹窗布局

使用Dialog或DialogFragment时,需要确保布局可以动态调整位置。示例布局文件:

XML 复制代码
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/dialog_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:id="@+id/dialog_content"
        android:layout_width="300dp"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:orientation="vertical"
        android:padding="16dp">
        <!-- 弹窗内容 -->
    </LinearLayout>
</FrameLayout>

动态调整弹窗位置代码

通过修改布局参数实现位置调整:

kotlin 复制代码
private fun adjustDialogPosition(keyboardHeight: Int) {
    val dialogContent = dialog.findViewById<View>(R.id.dialog_content)
    val params = dialogContent.layoutParams as FrameLayout.LayoutParams
    val screenHeight = resources.displayMetrics.heightPixels
    val targetY = (screenHeight - keyboardHeight) / 2 - dialogContent.height / 2
    params.topMargin = targetY
    dialogContent.layoutParams = params
}

private fun resetDialogPosition() {
    val dialogContent = dialog.findViewById<View>(R.id.dialog_content)
    val params = dialogContent.layoutParams as FrameLayout.LayoutParams
    params.topMargin = 0
    params.gravity = Gravity.CENTER
    dialogContent.layoutParams = params
}

处理WindowSoftInputMode

在AndroidManifest.xml中为Activity设置正确的软键盘模式:

XML 复制代码
<activity
    android:name=".YourActivity"
    android:windowSoftInputMode="adjustResize|stateHidden" />

注意事项

  1. 键盘高度计算需要排除系统状态栏和导航栏的影响
  2. 在横屏模式下需要特殊处理布局逻辑
  3. 不同Android版本可能存在行为差异,需要充分测试
  4. 对于DialogFragment,需要在onCreateView中获取根视图进行监听

是的,这是我直接使用AI生成的文章,看了下,大致都实现了,感觉现在博客这条下坡路确实要走到底了啊。

下面是我的代码:

java 复制代码
 @Override
    public void onStart() {
        super.onStart();
        // 在对话框显示后设置键盘监听
        setupKeyboardListener();
    }

    /**
     * 设置键盘监听
     */
    private void setupKeyboardListener() { 
        // 设置全局布局监听,检测键盘状态变化
        if (mContext instanceof android.app.Activity) {
            android.app.Activity activity = (android.app.Activity) mContext;
            View rootView = activity.findViewById(android.R.id.content);
            if (rootView != null) {
                mGlobalLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
                    @Override
                    public void onGlobalLayout() {
                        checkKeyboardStatus();
                    }
                };
                rootView.getViewTreeObserver().addOnGlobalLayoutListener(mGlobalLayoutListener);
            }
        }
    }
    
    /**
     * 检查键盘状态
     */
    private void checkKeyboardStatus() {
        if (mContext instanceof android.app.Activity) {
            android.app.Activity activity = (android.app.Activity) mContext;
            View rootView = activity.findViewById(android.R.id.content);
            if (rootView != null) {
                android.graphics.Rect rect = new android.graphics.Rect();
                rootView.getWindowVisibleDisplayFrame(rect);
                
                int screenHeight = rootView.getHeight();
                int visibleHeight = rect.bottom - rect.top;
                
                // 判断键盘是否弹起(可视区域高度小于屏幕高度的75%)
                boolean keyboardVisible = visibleHeight < screenHeight * 0.75;
                
                if (keyboardVisible && !isKeyboardShown) {
                    // 键盘弹起,计算对话框在剩余可见区域的居中位置
                    isKeyboardShown = true;
                    adjustDialogPosition(true, visibleHeight);
                } else if (!keyboardVisible && isKeyboardShown) {
                    // 键盘收起
                    isKeyboardShown = false;
                    adjustDialogPosition(false, screenHeight);
                }
            }
        }
    }
    
    /**
     * 调整对话框位置
     * @param keyboardShown 键盘是否显示
     * @param visibleHeight 可见区域高度
     */
    private void adjustDialogPosition(boolean keyboardShown, int visibleHeight) {
        if (getDialogHelper() == null) {
            return;
        }
        
        try {
            View contentView = getDialogHelper().getContentView();
            if (keyboardShown) {
                // 键盘弹起时,让对话框在剩余可见区域中居中显示
                getDialogHelper().setGravity(Gravity.CENTER_HORIZONTAL | Gravity.TOP);
                
                // 对话框高度(根据布局文件dialog_quick_greet.xml约246dp)
                int dialogHeight = (int) (246 * mContext.getResources().getDisplayMetrics().density);
                
                // 计算让对话框在可见区域居中的上边距
                // 公式:(可见区域高度 - 对话框高度) / 2
                int centeredTopMargin = (visibleHeight - dialogHeight) / 2;
                
                // 设置最小边距,避免对话框贴着屏幕顶部
                int minTopMargin = (int) (50 * mContext.getResources().getDisplayMetrics().density);
                int topMargin = Math.max(centeredTopMargin, minTopMargin);
                
                setContentViewMargin(contentView, topMargin);
            } else {
                // 键盘收起时,恢复默认的居中位置 自己的方法
                getDialogHelper().setGravity(Gravity.CENTER);
                setContentViewMargin(contentView, 0);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    /**
     * 设置内容视图的上边距
     */
    private void setContentViewMargin(View contentView, int topMargin) {
        if (contentView != null && contentView.getLayoutParams() instanceof android.view.ViewGroup.MarginLayoutParams) {
            android.view.ViewGroup.MarginLayoutParams params = 
                (android.view.ViewGroup.MarginLayoutParams) contentView.getLayoutParams();
            params.topMargin = topMargin;
            contentView.setLayoutParams(params);
        }
    }
相关推荐
cyforkk2 小时前
12、Java 基础硬核复习:集合框架(数据容器)的核心逻辑与面试考点
java·开发语言·面试
身如柳絮随风扬7 小时前
Java中的CAS机制详解
java·开发语言
风筝在晴天搁浅8 小时前
hot100 78.子集
java·算法
故事和你919 小时前
sdut-Java面向对象-06 继承和多态、抽象类和接口(函数题:10-18题)
java·开发语言·算法·面向对象·基础语法·继承和多态·抽象类和接口
Configure-Handler10 小时前
buildroot System configuration
java·服务器·数据库
:Concerto10 小时前
JavaSE 注解
java·开发语言·sprint
JMchen12311 小时前
现代Android图像处理管道:从CameraX到OpenGL的60fps实时滤镜架构
android·图像处理·架构·kotlin·android studio·opengl·camerax
电商API_1800790524711 小时前
第三方淘宝商品详情 API 全维度调用指南:从技术对接到生产落地
java·大数据·前端·数据库·人工智能·网络爬虫
一点程序11 小时前
基于SpringBoot的选课调查系统
java·spring boot·后端·选课调查系统
C雨后彩虹11 小时前
计算疫情扩散时间
java·数据结构·算法·华为·面试