• 全面屏虚拟按键高度适配


    需求场景:ScrollView中需要一个定高的recyclerView,其高度为屏幕高度,本以为一个简单的需求,调试了半天.

    最初的高度获取
    public static int getScreenHeight(Context context) {
    final Resources resources = context.getResources();
    final DisplayMetrics dm = resources.getDisplayMetrics();
    return dm.heightPixels;
    }
    复制代码测试结果(PS:测试机有限,欢迎更多人加入测试,发现未知的问题)

    手机类型
    getScreenHeight()
    getRealHeight()
    状态栏
    虚拟按键

    Mi8虚拟按键模式
    2120
    2340
    110
    130

    Mi8手势模式
    2120
    2340
    110
    130

    华为Mate20虚拟按键模式
    2094
    2244
    81
    114

    华为Mate20手势模式
    2163
    2244
    81
    114

    vivo-z20虚拟按键模式
    2154
    2280
    84
    126

    vivo-z20手势模式
    2280
    2280
    84
    126

    由测试可以看出,getScreenHeight()获取的高度在各平台是不统一的,原因也各异:

    理论上 getScreenHeight()获取的是可用高度,即屏幕整体高度减去占用的状态栏和虚拟按键.
    小米不区分是否使用了虚拟按键.
    华为,手势模式下正常,但虚拟按键模式高度有偏差.
    vivo,获取的高度多了状态栏高度.

    而获取真实高度,状态栏高度,虚拟按键高度,可以获取一致的值,因此最终方案采用 真实高度- 状态栏高度- 虚拟按键高度来获取真实的可用高度(PS:由于现今绝大部分项目都不使用ActionBar,所以未考虑ActionBar的影响).
    真实的可用高度获取(真实全屏高度- 状态栏高度- 虚拟按键高)

    获取真实高度

    public static int getRealHeight(Context context) {
        Display display = getDisplay(context);
        if (display == null) {
            return 0;
        }
        DisplayMetrics dm = new DisplayMetrics();
        display.getRealMetrics(dm);
        return dm.heightPixels;
    }
    

    复制代码
    状态栏高度

    public static int getStatusHeight() {
    int height = 0;
    int resourceId = Latte.getApplicationContext().getResources().getIdentifier("status_bar_height", "dimen", "android");
    if (resourceId > 0) {
    height = Latte.getApplicationContext().getResources().getDimensionPixelSize(resourceId);
    }
    return height;
    }
    复制代码
    虚拟按键是否使用

    检测是否是全面屏模式,如果是,不需考虑虚拟键
    检测虚拟按键是否隐藏了

    /**
     * 非全面屏下 虚拟按键是否打开
     *
     * @param activity activity
     * @return 虚拟按键是否打开
     */
    private static boolean isNavigationBarShown(Activity activity) {
        //虚拟键的view,为空或者不可见时是隐藏状态
        View view = activity.findViewById(android.R.id.navigationBarBackground);
        if (view == null) {
            return false;
        }
        int visible = view.getVisibility();
        if (visible == View.GONE || visible == View.INVISIBLE) {
            return false;
        } else {
            return true;
        }
    }
    
    /**
     * 全面屏(是否开启全面屏开关 0 关闭  1 开启)
     *
     * @param context activity
     * @return 是否是前面屏
     */
    private static boolean navigationGestureEnabled(Context context) {
        int val = Settings.Global.getInt(context.getContentResolver(), getDeviceInfo(), 0);
        return val != 0;
    }
    

    复制代码
    虚拟按键高度

    private static int getNavigationBarHeight(Context context) {
        int result = 0;
        int resourceId = context.getResources().getIdentifier("navigation_bar_height", "dimen", "android");
        if (resourceId > 0) {
          result = context.getResources().getDimensionPixelSize(resourceId);
        }
        return result;
    }
    

    复制代码
    可用高度
    有了上面这些信息,即可获取真实的可用区域高度: getScreenHeightReal(context) - getStatusHeight() - getNavigationBarHeightIfRoom(context)

    工具类路径
    相关知识(Display&&DisplayMetrics)

    DisplayMetrics: 提供屏幕的通用信息,如显示大小,分辨率和字体
    Display:提供逻辑显示区域大小、密度的相关信息

    本次用的的方法

    context.getResources().getDisplayMetrics(): 包含可视区域的屏幕信息的DisplayMetrics;
    activity.getWindowManager().getDefaultDisplay(): 获取当前屏幕信息的 Display;
    display.getMetrics(DisplayMetrics outMetrics): 将dispay的可视区信息填入outMetics;
    display.getRealMetrics(DisplayMetrics outMetrics) :将dispay的真实区域(即完整屏幕区域)信息填入outMetics;

    作者:wangfengye
    链接:https://juejin.cn/post/6844903829595504648
    来源:掘金
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 相关阅读:
    第八章 用通配符进行过滤
    第七章 数据过滤
    第六章 过滤数据
    第五章 排序和检索数据
    第四章 检索数据
    MySql 首记
    Effective C++ 6.继承与面向对象设计
    Effective C++ 5.实现
    ~~函数基础(五):内置函数~~
    ~~函数基础(四):递归函数~~
  • 原文地址:https://www.cnblogs.com/sishuiliuyun/p/14282344.html
Copyright © 2020-2023  润新知