美文网首页
安卓适配笔记【有关禁用文本上下文菜单、适配PC多窗口模式】

安卓适配笔记【有关禁用文本上下文菜单、适配PC多窗口模式】

作者: 天下第九九八十一 | 来源:发表于2021-07-19 17:51 被阅读0次

    一、为低版本(api<23)的设备优化文本选择的上下文菜单,动态隐藏顶部弹出的条形菜单,并适时恢复,使条形菜单不挤压布局、不覆盖输入框。

    低于等于安卓5的系统,选择文本后会在顶部弹出条形菜单,默认会挤压布局,将APP布局往下压。设置 FEATURE_ACTION_MODE_OVERLAY 可以解决挤压问题,将挤压变成覆盖。

    requestWindowFeature(Window.FEATURE_ACTION_MODE_OVERLAY);       
    
    supportRequestWindowFeature(Window.FEATURE_ACTION_MODE_OVERLAY);
    
    

    挤压布局的问题解决了,但又引入新的覆盖布局的问题 —— 如果在顶部有输入框,那么选择其中的文本后,条形菜单很有可能覆盖整个输入框。解决方法有两个,其一,将输入框移至布局底部,其二,将条形菜单动态隐藏、然后恢复显示。

    方法一需要修改布局,这不是我想要的。只能选方法二,激活输入框选择文本时隐藏条形菜单,退出时恢复显示。

    之所以多了恢复这一步,是因为我希望仅仅想屏蔽这一个输入框,而不是连带着连其他输入框或者WebView的上下文菜单也屏蔽了。

    那么说说隐藏EditText的上下文菜单的办法。非常简单粗暴,是直接将条形菜单从视图树中剔除,对安卓4、安卓5均有效。

    if(Utils.littleCake) {
        actionBarRoot = Utils.getNthParentNullable(root, 2);
        if (actionBarRoot instanceof ViewGroup && actionBarRoot.getId()==R.id.action_bar_root) {
            etSearch.setCustomSelectionActionModeCallback(new ActionMode.Callback() {
                View actionModeBar;
                Runnable restoreAbility = () -> {
                    if (actionModeBar!=null) {
                        Utils.addViewToParent(actionModeBar , (ViewGroup) actionBarRoot, 1);
                    }
                };
                @Override public boolean onPrepareActionMode(ActionMode mode, Menu menu) { return false; }
                @Override public void onDestroyActionMode(ActionMode mode) {
                    actionBarRoot.postDelayed(restoreAbility, 800); // 因为动画所以延迟调用 | wait for animation to end
                }
                @Override public boolean onCreateActionMode(ActionMode mode, Menu menu) {
                    actionBarRoot.removeCallbacks(restoreAbility);
                    actionModeBar = actionBarRoot.findViewById(R.id.action_mode_bar);
                    if (actionModeBar!=null) {
                        Utils.removeView(actionModeBar);
                    }
                    return true;
                }
                @Override public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
                    return false;
                }
            });
        }
    }
    

    这个方法简直前无古人,当别人还在用Java反射,反射的时候,我已经开始直接操作视图树了。这个思路,其实是研究Javascript带给我的灵感。

    效果如下:

    恢复要用postDelayed延迟恢复,因为 action mode bar 消失时有一个动画,需等待其结束再行恢复。延迟的 Runnable 我取名 restoreAbility ,其实是想到鸿蒙OS将安卓的Activity重命名为Ability,恶趣味一下,哈哈,毕竟 restoreRunnable 又长又不好看,还是 Ability 高大上一些。

    其他思路:解决条形菜单的覆盖问题,其实只要将条形菜单放到主界面后面就可以,所以 setElevation 应该是可以的,类似于设置渲染的 z-index,强行将主界面显示在前,不过仅仅在安卓5以上可以用。

    (代码仅展示片段,省略了一些Utils方法,不过稍后可以在《多聚浏览》开源项目中找到。)


    二、适配PC式多窗口

    我说的多窗口不是分屏,分屏只能被称作“两窗口”,它哪里可以被唤作“多”窗口了?

    PC式多窗口一般会在顶部多出一个标题栏,弹出PopupWindow时需考虑,不然对弹出位置有影响。

    星星星 Note5 的多窗口功能,来自2013年:

    星星星 S7 的多窗口功能,来自2017年:

    相关清单配置,声明支持多窗口:
    application { 👇 }

            <uses-library android:name="com.sec.android.app.multiwindow" android:required="false" />
            <meta-data android:name="com.sec.android.support.multiwindow" android:value="true" />
            <meta-data android:name="com.sec.android.multiwindow.DEFAULT_SIZE_W" android:value="632.0dip" />
            <meta-data android:name="com.sec.android.multiwindow.DEFAULT_SIZE_H" android:value="598.0dip" />
            <meta-data android:name="com.sec.android.multiwindow.MINIMUM_SIZE_W" android:value="632.0dip" />
            <meta-data android:name="com.sec.android.multiwindow.MINIMUM_SIZE_H" android:value="598.0dip" />
    

    声明切换多窗口、窗口大小变化等情况时,不重建activity:
    activity { 👇 }

    android:configChanges="orientation|keyboardHidden|screenSize|smallestScreenSize|screenLayout|uiMode|locale|layoutDirection|density|fontScale"
    

    题外话,星星星的软件系统真的很厉害,有许多领先的玩意儿,但是当它续航崩了后,就一点儿也不好用了。比如当初高价购入的s7,现在外屏碎,续航崩,bug多,只能当做“特种”调试机偶尔用用罢了,真是特别后悔、一键拉黑、再也不买。


    —— 全文完 ——

    相关文章

      网友评论

          本文标题:安卓适配笔记【有关禁用文本上下文菜单、适配PC多窗口模式】

          本文链接:https://www.haomeiwen.com/subject/eawcmltx.html