android 输出屏幕参数

99ANYc3cd6
预计阅读时长 34 分钟
位置: 首页 参数 正文

使用 WindowManager (最常用、最推荐)

这是在 Activity 或其他拥有 Window Context 的场景下最直接、最推荐的方法,它获取的是当前应用窗口的实际像素尺寸。

android 输出屏幕参数
(图片来源网络,侵删)

获取屏幕的宽度和高度 (像素)

// 在 Activity 中调用
fun getScreenSize() {
    // 1. 获取 WindowManager
    val windowManager = getSystemService(Context.WINDOW_SERVICE) as WindowManager
    // 2. 获取默认显示对象
    val display = windowManager.defaultDisplay
    // 3. 创建 DisplayMetrics 对象
    val outMetrics = DisplayMetrics()
    // 4. 将显示参数获取到 outMetrics 中
    display.getMetrics(outMetrics)
    // 5. 从 outMetrics 中取出宽高
    val screenWidthPixels = outMetrics.widthPixels
    val screenHeightPixels = outMetrics.heightPixels
    Log.d("ScreenParams", "屏幕宽度 (像素): $screenWidthPixels")
    Log.d("ScreenParams", "屏幕高度 (像素): $screenHeightPixels")
}

获取屏幕密度 (DPI) 和缩放比例

// 接续上面的代码
val density = outMetrics.density // 屏幕密度 (逻辑密度),2.0 表示 mdpi
val densityDpi = outMetrics.densityDpi // 屏幕密度 DPI,240 表示 hdpi
val scaledDensity = outMetrics.scaledDensity // 字体的缩放密度,通常和 density 相同
val xdpi = outMetrics.xdpi // 屏幕的物理 X DPI
val ydpi = outMetrics.ydpi // 屏幕的物理 Y DPI
Log.d("ScreenParams", "屏幕密度 (density): $density")
Log.d("ScreenParams", "屏幕密度 DPI (densityDpi): $densityDpi")
Log.d("ScreenParams", "字体缩放密度 (scaledDensity): $scaledDensity")
Log.d("ScreenParams", "物理 X DPI: $xdpi")
Log.d("ScreenParams", "物理 Y DPI: $ydpi")

计算屏幕的物理尺寸 (英寸)

利用勾股定理计算屏幕对角线的物理长度。

// 接续上面的代码
val screenWidthInches = outMetrics.widthPixels / xdpi
val screenHeightInches = outMetrics.heightPixels / ydpi
val screenDiagonalInches = sqrt(screenWidthInches * screenWidthInches + screenHeightInches * screenHeightInches)
Log.d("ScreenParams", "屏幕物理宽度 (英寸): $screenWidthInches")
Log.d("ScreenParams", "屏幕物理高度 (英寸): $screenHeightInches")
Log.d("ScreenParams", "屏幕对角线尺寸 (英寸): $screenDiagonalInches") // 这就是我们常说的手机尺寸,如 6.1英寸

使用 ResourcesDisplayMetrics

这种方法也非常方便,尤其在需要处理资源时。Resources 对象本身就持有一个 DisplayMetrics 实例。

fun getScreenSizeWithResources() {
    // Resources 对象会自动管理 DisplayMetrics
    val resources = resources
    val displayMetrics = resources.displayMetrics
    val screenWidthPixels = displayMetrics.widthPixels
    val screenHeightPixels = displayMetrics.heightPixels
    val densityDpi = displayMetrics.densityDpi
    Log.d("ScreenParams_Resources", "屏幕宽度 (像素): $screenWidthPixels")
    Log.d("ScreenParams_Resources", "屏幕高度 (像素): $screenHeightPixels")
    Log.d("ScreenParams_Resources", "屏幕密度 DPI: $densityDpi")
}

注意: ResourcesDisplayMetrics 在横竖屏切换或系统 DPI 设置改变时会自动更新,但不会实时反映当前窗口的状态(分屏模式下,它返回的是整个屏幕的尺寸,而不是当前分屏窗口的尺寸),对于精确获取窗口尺寸,WindowManager 仍然是首选。


使用 WindowInsets (获取安全区域)

现代 Android 应用需要考虑状态栏、导航栏等系统UI元素。WindowInsets 可以帮助你获取这些信息,从而计算出真正的“可用”屏幕区域。

android 输出屏幕参数
(图片来源网络,侵删)

这对于实现沉浸式体验或全屏布局非常有用。

// 在 Activity 的 onCreate 或 onWindowFocusChanged 中调用
fun getUsableScreenSize() {
    // 使用 ViewCompat 获取 WindowInsets,兼容性更好
    ViewCompat.setOnApplyWindowInsetsListener(window.decorView) { view, insets ->
        // 获取状态栏高度
        val statusBarHeight = insets.getInsets(WindowInsets.Type.statusBars()).top
        // 获取导航栏高度 (可能在底部或侧边)
        val navigationBarHeight = insets.getInsets(WindowInsets.Type.navigationBars()).bottom
        // 可用屏幕尺寸 = 屏幕总尺寸 - 系统UI区域
        val usableWidth = insets.getInsets(WindowInsets.Type.systemBars()).left + insets.getInsets(WindowInsets.Type.systemBars()).right
        val usableHeight = insets.getInsets(WindowInsets.Type.systemBars()).top + insets.getInsets(WindowInsets.Type.systemBars()).bottom
        // 注意:这里为了简化,直接用屏幕总尺寸减去 insets
        // 更精确的计算方式如下:
        val displayMetrics = DisplayMetrics()
        windowManager.defaultDisplay.getMetrics(displayMetrics)
        val totalWidth = displayMetrics.widthPixels
        val totalHeight = displayMetrics.heightPixels
        val actualUsableWidth = totalWidth - usableWidth
        val actualUsableHeight = totalHeight - usableHeight
        Log.d("WindowInsets", "状态栏高度: $statusBarHeight")
        Log.d("WindowInsets", "导航栏高度: $navigationBarHeight")
        Log.d("WindowInsets", "可用宽度: $actualUsableWidth")
        Log.d("WindowInsets", "可用高度: $actualUsableHeight")
        // 返回 insets 以便后续视图可以使用
        insets
    }
}

使用 ViewTreeObserver (监听尺寸变化)

如果你想在屏幕尺寸发生变化(如键盘弹出、横竖屏切换)时执行某些操作,可以使用 ViewTreeObserver

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    val rootLayout = findViewById<View>(android.R.id.content)
    rootLayout.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
        override fun onGlobalLayout() {
            // 当布局完成或尺寸变化时调用
            val width = rootLayout.width
            val height = rootLayout.height
            Log.d("ViewTreeObserver", "当前布局尺寸 - 宽: $width, 高: $height")
            // 注意:为了避免重复调用,在不需要时移除监听器
            // API 16+ 使用 isAlive 检查
            if (rootLayout.viewTreeObserver.isAlive) {
                rootLayout.viewTreeObserver.removeOnGlobalLayoutListener(this)
            }
        }
    })
}

总结与最佳实践

方法 适用场景 优点 缺点
WindowManager 通用,获取精确的窗口尺寸和屏幕密度 最直接、最准确,能反映当前窗口状态 需要处理 WINDOW_SERVICE
Resources 需要访问资源或了解设备配置时 非常方便,与资源系统紧密集成 不反映当前窗口状态(如分屏)
WindowInsets 处理安全区域,实现沉浸式布局 能精确获取系统UI区域,实现更灵活的UI API 较新,需要处理兼容性
ViewTreeObserver 监听视图尺寸的实时变化 能在尺寸变化时得到回调 需要手动管理监听器的添加和移除

完整示例代码 (Kotlin):

你可以创建一个 Activity,将下面的代码粘贴进去运行,就能看到所有输出。

android 输出屏幕参数
(图片来源网络,侵删)
import android.content.Context
import android.os.Bundle
import android.util.DisplayMetrics
import android.util.Log
import android.view.View
import android.view.WindowManager
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        // 1. 使用 WindowManager 获取屏幕参数
        getScreenParamsByWindowManager()
        // 2. 使用 Resources 获取屏幕参数
        getScreenParamsByResources()
        // 3. 使用 WindowInsets 获取安全区域
        getSafeAreaByWindowInsets()
    }
    private fun getScreenParamsByWindowManager() {
        Log.d("--- WindowManager 方法 ---", "开始获取...")
        val windowManager = getSystemService(Context.WINDOW_SERVICE) as WindowManager
        val display = windowManager.defaultDisplay
        val outMetrics = DisplayMetrics()
        display.getMetrics(outMetrics)
        val widthPixels = outMetrics.widthPixels
        val heightPixels = outMetrics.heightPixels
        val density = outMetrics.density
        val densityDpi = outMetrics.densityDpi
        val xdpi = outMetrics.xdpi
        val ydpi = outMetrics.ydpi
        // 计算物理尺寸
        val widthInches = widthPixels / xdpi
        val heightInches = heightPixels / ydpi
        val diagonalInches = kotlin.math.sqrt(widthInches * widthInches + heightInches * heightInches)
        Log.d("WindowManager", "宽度 (像素): $widthPixels")
        Log.d("WindowManager", "高度 (像素): $heightPixels")
        Log.d("WindowManager", "密度: $density")
        Log.d("WindowManager", "密度 DPI: $densityDpi")
        Log.d("WindowManager", "物理尺寸 (英寸): %.2f".format(diagonalInches))
    }
    private fun getScreenParamsByResources() {
        Log.d("--- Resources 方法 ---", "开始获取...")
        val displayMetrics = resources.displayMetrics
        Log.d("Resources", "宽度 (像素): ${displayMetrics.widthPixels}")
        Log.d("Resources", "高度 (像素): ${displayMetrics.heightPixels}")
        Log.d("Resources", "密度 DPI: ${displayMetrics.densityDpi}")
    }
    private fun getSafeAreaByWindowInsets() {
        Log.d("--- WindowInsets 方法 ---", "开始获取...")
        val rootLayout = findViewById<View>(android.R.id.content)
        ViewCompat.setOnApplyWindowInsetsListener(rootLayout) { _, insets ->
            val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
            val statusBarHeight = systemBars.top
            val navigationBarHeight = systemBars.bottom
            Log.d("WindowInsets", "状态栏高度: $statusBarHeight")
            Log.d("WindowInsets", "导航栏高度: $navigationBarHeight")
            insets // 必须返回 insets
        }
    }
}

重要提示:

  • widthPixelsheightPixels 是指设备屏幕上可用的像素数量,包含了系统UI(如状态栏)。
  • densityDpi 是 Android 系统用来适配不同屏幕密度的关键值。mdpi (160), hdpi (240), xhdpi (320), xxhdpi (480) 等。
  • 横竖屏: 如果你的应用支持横竖屏,记得在 AndroidManifest.xml 中为 <activity> 标签添加 android:configChanges="orientation|screenSize",并在 onConfigurationChanged 中重新获取屏幕参数,以避免 Activity 重建带来的性能开销。
-- 展开阅读全文 --
头像
宏基aspire4738g拆机步骤详细吗?
« 上一篇 昨天
APC BK650 UPS拆机后内部有何玄机?
下一篇 » 昨天

相关文章

取消
微信二维码
支付宝二维码

最近发表

标签列表

目录[+]