android实现底部弹出框与软键盘冲突(全面屏虚拟键适配)

本文分享了解决Android中Dialog与软键盘冲突的方法,通过使用DialogActivity并自定义主题样式,实现了点击外部区域仅关闭软键盘的效果,并解决了全面屏手机虚拟键导致的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    普通的底部弹出框大家都可以很熟练的使用了,无非是一个diaolog的事情,但是当dialog中含有输入框之后,软键盘与dialog的冲突可以说是十分坑了。。。更别说加上底部虚拟键了,这么一个小功能磨得我简直吐血。。。下面就是我的血泪史。 

第一阶段:    

  首先是底部dialog与软键盘的冲突:

       View myView = LayoutInflater.from(MainActivity.this).inflate(R.layout.pop,null);
        myView.setPadding(0, 0, 0, 0);
        Dialog dialog = new AlertDialog.Builder(MainActivity.this)
                .setView(myView).create();
        //设置点击Dialog外部任意区域关闭Dialog
        dialog.setCanceledOnTouchOutside(true);
        dialog.show();
        Window window = dialog.getWindow();            
        win.getDecorView().setPadding(0, 0, 0, ScreenUtils.getNavigationBarHeight(this));
        WindowManager.LayoutParams lp = win.getAttributes();
       lp.width = WindowManager.LayoutParams.MATCH_PARENT;
       lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
       lp.gravity = Gravity.BOTTOM;//设置对话框置底部显示

       win.setAttributes(lp);

      这时候dialog中的布局文件即R.layout.pop中含有edittext,每次我输入后想关闭软键盘,就顺手点击diaolog外部区域,这下好了。。。不仅软键盘关闭了,dialog也一起dimiss了。。。然后想着那就不让点击Dialog外部任意区域关闭Dialog生效呗,就把 dialog.setCanceledOnTouchOutside(true);这行代码注释掉,再运行,ok,我点即外部区域果然不会让dialog消失,但问题是软键盘也坚挺如初,毫不动摇,我手机自带的输入法当输入中文时候没有点击收起的小箭头。。。这下怎么搞。。。我想要点击外部diaolog不消失,只让软键盘消失啊!!!然后疯狂百度,得到解决方法如下:

      不使用dialog而是使用dialogActivity,嘿嘿,这样软键盘总不会和dialog纠缠不清,同上同下了吧。

   setContentView(R.layout.activity_main); 

       //设置窗口对齐屏幕宽度

    Window win = this.getWindow();
    win.getDecorView().setPadding(0, 0, 0, 0);
    WindowManager.LayoutParams lp = win.getAttributes();
    lp.width = WindowManager.LayoutParams.MATCH_PARENT;
    lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
    lp.gravity = Gravity.BOTTOM;//设置对话框置顶显示
    win.setAttributes(lp);
    //设置点击外部空白处可以关闭Activity,但我们不需要

    //this.setFinishOnTouchOutside(true); 

     当前activity要继承自AppCompatActivity,然后重写

@Override
public boolean onTouchEvent(MotionEvent event) {
    // TODO Auto-generated method stub
    if(event.getAction() == MotionEvent.ACTION_DOWN){
        if(getCurrentFocus()!=null && getCurrentFocus().getWindowToken()!=null){
            InputMethodManager manager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
            manager.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
        }
    }
    return super.onTouchEvent(event);
}
  这样,点击外部,就会让软键盘收起,且dialog不消失了(毕竟是activity了)

    当然,要在表单中注册这个activity

 <activity android:name=".MainActivity"      android:theme="@style/Base.V7.Theme.AppCompat.Light.Dialog"></activity>

   但是!!又双叒叕出问题了。。。activity撑不满屏宽啊,这肯定是样式问题了,我们看看这个dialog样式是怎样的吧

<style name="Base.V7.Theme.AppCompat.Light.Dialog" parent="Base.Theme.AppCompat.Light">
    <item name="android:colorBackground">?attr/colorBackgroundFloating</item>
    <item name="android:colorBackgroundCacheHint">@null</item>

    <item name="android:windowFrame">@null</item>
    <item name="android:windowTitleStyle">@style/RtlOverlay.DialogWindowTitle.AppCompat</item>
    <item name="android:windowTitleBackgroundStyle">@style/Base.DialogWindowTitleBackground.AppCompat</item>
    <item name="android:windowBackground">@drawable/abc_dialog_material_background</item>
    <item name="android:windowIsFloating">true</item>
    <item name="android:backgroundDimEnabled">true</item>
    <item name="android:windowContentOverlay">@null</item>
    <item name="android:windowAnimationStyle">@style/Animation.AppCompat.Dialog</item>
    <item name="android:windowSoftInputMode">stateUnspecified|adjustPan</item>

    <item name="windowActionBar">false</item>
    <item name="windowActionModeOverlay">true</item>

    <item name="listPreferredItemPaddingLeft">24dip</item>
    <item name="listPreferredItemPaddingRight">24dip</item>

    <item name="android:listDivider">@null</item>
</style>

这么多属性啊。。。好烦啊,一个个试,是哪个属性影响了全屏,结果发现了这个妖艳贱货

<item name="android:windowBackground">@drawable/abc_dialog_material_background</item>
<style name="noTitleDialogActivity" parent="Base.Theme.AppCompat.Light">
    <item name="android:colorBackground">?attr/colorBackgroundFloating</item>
    <item name="android:colorBackgroundCacheHint">@null</item>

    <item name="android:windowFrame">@null</item>
    <item name="android:windowTitleStyle">@style/RtlOverlay.DialogWindowTitle.AppCompat</item>
    <item name="android:windowTitleBackgroundStyle">@style/Base.DialogWindowTitleBackground.AppCompat</item>
    
<!--<item name="android:windowBackground">@drawable/abc_dialog_material_background</item>-->     //这个布局会让activity无法占满屏幕
<item name="android:windowIsFloating">true</item> <item name="android:backgroundDimEnabled">true</item> <item name="android:windowContentOverlay">@null</item> <item name="android:windowAnimationStyle">@style/Animation.AppCompat.Dialog</item> <item name="android:windowSoftInputMode">stateUnspecified|adjustPan</item> <item name="windowActionBar">false</item> <item name="windowActionModeOverlay">true</item> <item name="listPreferredItemPaddingLeft">24dip</item> <item name="listPreferredItemPaddingRight">24dip</item> <item name="android:listDivider">@null</item></style>

theme中使用自己的样式,注释掉他!完美!全屏了!


第二阶段:

美滋滋的给测试测了,结果新问题穿线在全面屏手机虚拟键上,由于我的activity(包括dialogactivity都是使用沉浸样式)虚拟键区域在弹出框中会覆盖我的diaolog布局,而我的布局在地段有个提交按钮。。。你倒是给我浮起来一点啊!好吧,你赢了,我去获取你虚拟区域的高度可以吧,来给我的activity加个内增高,于是

Window win;//全局变量

win = this.getWindow();
win.getDecorView().setPadding(0, 0, 0, ScreenUtils.getNavigationBarHeight(this));
WindowManager.LayoutParams lp = win.getAttributes();
lp.width = WindowManager.LayoutParams.MATCH_PARENT;
lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
lp.gravity = Gravity.BOTTOM;//设置对话框置底部显示
 win.setAttributes(lp);

但是,软键盘遮挡我的输入框又出现了,好吧,我监听你的软键盘弹出收起,然后一样给我的activity加个可活动的内增高,这下可行了吧,在activity中加个监听,另外新建一个帮助类

SoftKeyBoardListener.setListener(CheckDialogActivity.this, new SoftKeyBoardListener.OnSoftKeyBoardChangeListener() {
    @Override
    public void keyBoardShow(int height) {
        win.getDecorView().setPadding(0, 0, 0, height);
        WindowManager.LayoutParams lp = win.getAttributes();
        lp.width = WindowManager.LayoutParams.MATCH_PARENT;
        lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
        lp.gravity = Gravity.BOTTOM;//设置对话框置底部显示
        win.setAttributes(lp);
    }

    @Override
    public void keyBoardHide(int height) {
        win.getDecorView().setPadding(0, 0, 0, ScreenUtils.getNavigationBarHeight(CheckDialogActivity.this));
        WindowManager.LayoutParams lp = win.getAttributes();
        lp.width = WindowManager.LayoutParams.MATCH_PARENT;
        lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
        lp.gravity = Gravity.BOTTOM;//设置对话框置底部显示
        win.setAttributes(lp);
    }
});

public class SoftKeyBoardListener {
    private View rootView;//activity的根视图
    int rootViewVisibleHeight;//纪录根视图的显示高度
    private OnSoftKeyBoardChangeListener onSoftKeyBoardChangeListener;

    public SoftKeyBoardListener(Activity activity) {
        //获取activity的根视图
        rootView = activity.getWindow().getDecorView();

        //监听视图树中全局布局发生改变或者视图树中的某个视图的可视状态发生改变
        rootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                //获取当前根视图在屏幕上显示的大小
                Rect r = new Rect();
                rootView.getWindowVisibleDisplayFrame(r);

                int visibleHeight = r.height();
                System.out.println(""+visibleHeight);
                if (rootViewVisibleHeight == 0) {
                    rootViewVisibleHeight = visibleHeight;
                    return;
                }

                //根视图显示高度没有变化,可以看作软键盘显示/隐藏状态没有改变
                if (rootViewVisibleHeight == visibleHeight) {
                    return;
                }

                //根视图显示高度变小超过200,可以看作软键盘显示了
                if (rootViewVisibleHeight - visibleHeight > 200) {
                    if (onSoftKeyBoardChangeListener != null) {
                        onSoftKeyBoardChangeListener.keyBoardShow(rootViewVisibleHeight - visibleHeight);
                    }
                    rootViewVisibleHeight = visibleHeight;
                    return;
                }

                //根视图显示高度变大超过200,可以看作软键盘隐藏了
                if (visibleHeight - rootViewVisibleHeight > 200) {
                    if (onSoftKeyBoardChangeListener != null) {
                        onSoftKeyBoardChangeListener.keyBoardHide(visibleHeight - rootViewVisibleHeight);
                    }
                    rootViewVisibleHeight = visibleHeight;
                    return;
                }

            }
        });
    }

    private void setOnSoftKeyBoardChangeListener(OnSoftKeyBoardChangeListener onSoftKeyBoardChangeListener) {
        this.onSoftKeyBoardChangeListener = onSoftKeyBoardChangeListener;
    }

    public interface OnSoftKeyBoardChangeListener {
        void keyBoardShow(int height);

        void keyBoardHide(int height);
    }

    public static void setListener(Activity activity, OnSoftKeyBoardChangeListener onSoftKeyBoardChangeListener) {
        SoftKeyBoardListener softKeyBoardListener = new SoftKeyBoardListener(activity);
        softKeyBoardListener.setOnSoftKeyBoardChangeListener(onSoftKeyBoardChangeListener);
    }
}

当你弹起多少,我就给activity上移多少,你收起,我就设置高度为虚拟栏高度,这下,总算搞定你这个磨人的小妖精了。。。  



第一次写这么多,大家点个赞可好!

<think>嗯,用户想了解CRC32校验算法的实现和使用方法。我需要先回顾一下CRC32的基本原理,然后考虑如何用简单易懂的中文解释清楚。首先,CRC32是基于循环冗余校验的一种算法,主要用于检测数据传输或存储中的错误。用户可能希望知道它的具体步骤,比如如何初始化、处理数据、异或操作以及最终得到校验值。 根据提供的引用资料,CRC32的核心是多项式除法,但实际中通过查表法优化速度。需要解释生成多项式,比如常见的0xEDB88320,以及初始值、输入输出是否反转这些参数。用户提供的代码片段中有两个版本,一个是逐位计算,另一个是查表法,这可能需要在回答中对比说明,突出查表法的效率优势。 接下来,用户可能关心具体怎么使用这个算法,比如在C语言中的实现步骤,或者如何应用到实际项目中,比如文件校验或网络传输。要分步骤讲解,从初始化到处理每个字节,再到最终计算,可能需要示例代码来辅助说明。同时,注意用户要求行内数学表达式用$...$,比如多项式应该写成$0xEDB88320$这样的格式。 另外,用户的问题里提到生成相关问题,我需要考虑相关的问题可能涉及性能优化、不同生成多项式的影响,或者CRC32与其他校验算法的比较。这些可以作为相关问题放在最后,帮助用户进一步探索。 需要确保回答结构清晰,先讲原理,再讲实现步骤,然后使用方法,最后附上相关问题。同时,引用提供的资料,比如引用[^1]和[^2]来支持解释。要避免技术术语过于复杂,保持语言通俗易懂,同时满足LaTeX格式要求,比如多项式用$符号包裹。检查是否有遗漏的步骤,比如输入反转和输出反转的处理,这在代码示例中有所体现,需要解释清楚这些参数的作用。</think>### CRC32校验算法实现及使用方法 #### 一、CRC32基本原理 CRC32通过多项式除法生成32位校验值,用于检测数据传输或存储中的错误。其核心是生成多项式$G(x)$,常用标准为$0xEDB88320$(反向多项式形式)[^1]。算法流程如下: 1. **初始化**:设置32位寄存器初值为$0xFFFFFFFF$ 2. **数据输入**:逐字节与寄存器异或运算 3. **位移处理**:根据多项式进行循环移位和异或操作 4. **结果取反**:最终值与$0xFFFFFFFF$异或 #### 二、算法实现(C语言) ```c // 查表法实现(高效) uint32_t crc32_table[256]; void init_crc32_table() { for (int i = 0; i < 256; i++) { uint32_t crc = i; for (int j = 0; j < 8; j++) { crc = (crc >> 1) ^ ((crc & 1) ? 0xEDB88320 : 0); } crc32_table[i] = crc; } } uint32_t calc_crc32(uint8_t *data, size_t len) { uint32_t crc = 0xFFFFFFFF; while (len--) { crc = (crc >> 8) ^ crc32_table[(crc ^ *data++) & 0xFF]; } return crc ^ 0xFFFFFFFF; } ``` 此实现通过预先生成的256元素查找表,将时间复杂度从$O(n \cdot 8)$优化到$O(n)$。 #### 三、使用场景及方法 1. **文件校验**:计算文件CRC32值验证完整性 ```bash $ crc32 filename.txt ``` 2. **网络传输**:在数据帧尾部附加4字节校验码 3. **存储系统**:RAID、ZFS等文件系统使用CRC32校验数据块 #### 四、参数配置 | 参数 | 说明 | 标准值 | |---------------|---------------------------|-----------------| | 初始值 | 寄存器初始状态 | 0xFFFFFFFF | | 多项式 | 生成多项式 | 0xEDB88320 | | 输入/输出反转 | 字节处理顺序 | 通常需要反转 |
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值