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
    }
}
相关推荐
plainGeekDev34 分钟前
null 判断 → Kotlin 可空类型
android·java·kotlin
plainGeekDev37 分钟前
getter/setter → Kotlin 属性
android·java·kotlin
YXL1111YXL2 小时前
Handler 消息回收与协程异步执行的时序陷阱
android
恋猫de小郭3 小时前
KMP / CMP 鸿蒙版本 Beta 发布,他有什么特别之处?
android·前端·flutter
三少爷的鞋3 小时前
Android 协程并发控制:别动线程池,控制好并发语义就够了
android
weiggle20 小时前
第七篇:状态提升与单向数据流——架构设计的核心
android
xingpanvip20 小时前
星盘接口开发文档:本命盘接口指南
android·开发语言·css·php·lua
goldenrolan20 小时前
A公司物料替代测试系统 v1.7:从需求到 exe/apk 的 AI 辅助全链路实践
android·自动化测试·软件测试·python·ai
AC赳赳老秦21 小时前
用 OpenClaw 搭建服务器故障应急响应系统,自动处理 80% 常见运维故障
android·运维·服务器·python·rxjava·deepseek·openclaw
骇客之技术1 天前
AutoLua:在安卓上写 Lua 脚本
android·junit·lua