Android中获取当前设备的宽高与屏幕密度等数据的工具类

文章目录


ScreenSizeUtil

在 Android 开发中,获取屏幕尺寸是高频需求,但不同系统版本(尤其是 API 30 前后)的 API 差异、状态栏 / 导航栏的扣除逻辑、分屏 / 折叠屏适配等问题,很容易导致尺寸计算错误。本文分享一套兼容所有 Android 版本的屏幕尺寸工具类,支持获取设备物理尺寸、应用可用尺寸,还能单独获取状态栏 / 导航栏高度,解决日常开发中 99% 的屏幕尺寸适配问题

完整工具类

kotlin 复制代码
object ScreenSizeUtil {


    /**
     *  @describe: 获取当前设备的宽高,包含了状态栏、导航栏
     *   1.忽略了分屏、画中画,始终返回当前设备最大尺寸
     *   2.折叠屏时返回展开态时的设备最大尺寸
     *  @params:
     *  @return: Pair<Int,Int> 宽度与高度
     */

    fun getScreenDevicesSize(context: Context): Pair<Int, Int> {

        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { //30以上的适配
            val bounds = context.windowManager.maximumWindowMetrics.bounds //获取当前设备的屏幕信息
            bounds.height()
            Pair(bounds.width(), bounds.height())
        } else { //低版本适配

            //方法1 获取实际的物理尺寸,包含状态栏跟导航栏
            val display = context.displayManager.getDisplay(Display.DEFAULT_DISPLAY)
            val physicalWidth = display.mode.physicalWidth
            val physicalHeight = display.mode.physicalHeight
            Pair(physicalWidth, physicalHeight)

            //方法2 获取实际的物理尺寸,包含状态栏跟导航栏
            /*val display = context.windowManager.defaultDisplay
            val point = Point()
            display.getRealSize(point)
            Pair(point.x,point.y)*/
        }
    }


    /**
     *  @describe: 获取应用可用高度,减去了状态栏、导航栏
     *        1.返回画中画、分屏中当前窗口占用的区域,
     *        2.折叠屏时返回折叠态的小屏高度
     *  @params:
     *  @return: Pair<Int,Int> 宽度与高度
     */
    fun getAppUsableSize(context: Context): Pair<Int, Int> {
        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            val windowManager =
                context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
            val windowMetrics = windowManager.currentWindowMetrics //获取当前窗口的信息
            val insets = windowMetrics.windowInsets
                .getInsetsIgnoringVisibility(android.view.WindowInsets.Type.systemBars()) //排除系统插入区域(状态栏+导航栏)后的可见区域
            // 应用高度 = 窗口高度 - 状态栏高度 - 导航栏高度
            val height = windowMetrics.bounds.height() - insets.top - insets.bottom
            val width = windowMetrics.bounds.width() - insets.left - insets.right

            Pair(width, height)
        } else {
            // 方法1 获取当前窗口的宽高
            val decorView = (context as android.app.Activity).window.decorView
            val outRect = Rect()
            decorView.getWindowVisibleDisplayFrame(outRect)
            Pair(outRect.right - outRect.left, outRect.bottom - outRect.top)


            //方法2 获取当前窗口的宽高
            /* val meterics = DisplayMetrics()
             context.windowManager.defaultDisplay.getMetrics(meterics)
             Pair(meterics.widthPixels,meterics.heightPixels - getStatusBarHeight(context)) //老版本默认包含状态栏*/

            //方法3.获取当前窗口的宽高
            /*val display = context.windowManager.defaultDisplay
            val point = Point()
            display.getSize(point)
            Pair(point.x,point.y - getStatusBarHeight(context)) //老版本默认包含状态栏*/
        }

    }

    /**
     * 获取状态栏高度
     *
     * @param context
     * @return
     */
    fun getStatusBarHeight(context: Context): Int {
        val resourceId =
            context.resources.getIdentifier("status_bar_height", "dimen", "android")
        return context.resources.getDimensionPixelSize(resourceId)
    }

    /**
     * 获取导航栏高度
     *
     * @param context
     * @return
     */
    fun getNavigationBarHeight(context: Context): Int {
        val resourceId =
            context.resources.getIdentifier("navigation_bar_height", "dimen", "android")
        return context.resources.getDimensionPixelSize(resourceId)
    }

    /**
     *  @describe: 返回当前屏幕的密度
     *  @params: 上下文
     *  @return:
     */
    fun getDisplayMetrics(context: Context): Float {
        val displayMetrics = DisplayMetrics()
        context.windowManager.defaultDisplay.getMetrics(displayMetrics)
        return displayMetrics.density
    }
}
相关推荐
黄林晴7 小时前
Koin 开发者炸了!7 条规则根治运行时错误,自动扫描太香了
android
恋猫de小郭7 小时前
Flutter 3.41.8 又双叒修复调试问题,草台班子日常 hotfix
android·前端·flutter
火山上的企鹅8 小时前
QGC 二次开发(RTK):内置 NTRIP Client,实现 CORS 差分数据接入与 GPS_RTCM_DATA 转发
android·无人机·rtk·qgroundcontrol
Kapaseker8 小时前
客官,你误会 Compose Strong Skipping 了
android·kotlin
张风捷特烈8 小时前
状态管理大乱斗#04 | Riverpod 源码评析 (上) - 核心架构
android·前端·flutter
大鹏说大话8 小时前
构造函数属性提升的利与弊:如何优雅地编写价值对象(Value Object)
android
大黄说说8 小时前
匹配表达式 vs. Switch语句:现代PHP中的条件逻辑重构
android·ide·android studio
fred_kang8 小时前
MySQL锁表诊断与解决方案
android·mysql·mariadb
未来之窗软件服务8 小时前
CICD 信发系统自动打包安卓签名apk—无相无界(7)—东方仙盟
android·仙盟创梦ide·东方仙盟·东方仙盟无相无界
Mr -老鬼8 小时前
零基础玩转 EasyClick+ESP32 OTG有线HID|零权限超高稳定手机操控
android·智能手机