一、废弃和限制

Android 12

在 Android 12 中,我们继续建议使用 WindowMetrics,并且正在逐步废弃以下方法:

Display.getRealSize()
Display.getRealMetrics()

Android 11 中引入了 WindowMetrics,可让开发者轻松查询与窗口相关的指标,例如,窗口的位置和大小,以及任何系统边衬区。我们在此版本中向后移植了 API,以便开发者能够利用 WindowMetrics,并继续支持旧版 Android。

可以通过 WindowManager#getCurrentWindowMetrics() 和 WindowManager#getMaximumWindowMetrics() API 获取 WindowMetrics。

https://developer.android.google.cn/reference/android/view/WindowMetrics

Android 11

在 Android 11 中,我们引入了 WindowMetrics API 并废弃了以下方法:

Display.getSize()
Display.getMetrics()

二、WindowMetrics( android.view.WindowMetrics)

2.1、获取WindowMetrics实例

getMaximumWindowMetrics()getCurrentWindowMetrics()都是WindowManager类的方法,用于获取窗口度量信息,但它们在用途和返回结果上有所区别。

  1. getMaximumWindowMetrics():

    • 该方法是Android 12(API级别31)中新增的。
    • 用于获取当前设备上的最大窗口度量信息,即设备屏幕的完整尺寸。
    • 返回的WindowMetrics对象包含了设备屏幕的完整度量信息,包括屏幕的大小、位置和可见区域等。
    • 通过调用getMaximumWindowMetrics().getWindowMetrics()方法,可以获取到完整的WindowMetrics对象。
    • Jetpack 方法 WindowMetricsCalculator.computeMaximumWindowMetrics() 同样用途
  2. getCurrentWindowMetrics():

    • 该方法在Android 11(API级别30)及更高版本中可用。
    • 用于获取当前窗口的度量信息,即应用程序窗口的大小、位置和可见区域等。
    • 返回的WindowMetrics对象包含了当前窗口的度量信息,包括窗口的大小、位置和可见区域等。
    • 通过调用windowManager.getCurrentWindowMetrics().getWindowMetrics()方法,可以获取到当前窗口的完整的WindowMetrics对象。
    • Jetpack 的 WindowMetricsCalculator.computeCurrentWindowMetrics()。同样用途

总结而言,getMaximumWindowMetrics()方法用于获取设备屏幕的完整度量信息,而windowManager.getCurrentWindowMetrics()方法用于获取当前窗口的度量信息。前者提供了整个设备屏幕的度量信息,而后者提供了当前窗口的度量信息。

需要注意的是,这些方法的返回值是WindowMetrics对象,可以通过该对象获取有关窗口的详细度量信息,如窗口大小、位置和可见区域等。

2.2、API 31

windowInsets

https://developer.android.google.cn/reference/kotlin/android/view/WindowInsets

getInsetsIgnoringVisibility()

指定可见区域排除下面的哪部分(参数指定)。

getInsetsIgnoringVisibility() 方法是 WindowInsets 类的方法,它接受一个或多个参数来指定你感兴趣的插入区域类型。以下是一些常用的参数:

  • WindowInsets.Type.systemBars():指定系统栏的插入区域,包括状态栏和导航栏。
  • WindowInsets.Type.ime():指定输入法编辑器(IME)的插入区域,包括软键盘。
  • WindowInsets.Type.ime() or WindowInsets.Type.systemBars():同时指定输入法编辑器和系统栏的插入区域。
  • WindowInsets.Type.navigationBars():指定导航栏的插入区域。
  • WindowInsets.Type.statusBars():指定状态栏的插入区域。
  • WindowInsets.Type.displayCutout():指定显示切口(如刘海屏或凹口屏)的插入区域。

你可以根据需要选择一个或多个参数,以获取你想要的插入区域。例如,如果你想获取系统栏和导航栏的插入区域,可以使用 WindowInsets.Type.systemBars() or WindowInsets.Type.navigationBars()

请注意,插入区域的可用性和行为取决于设备的硬件和系统版本。不同的设备和 Android 版本可能会提供不同的插入区域类型和行为。因此,在使用特定插入区域之前,建议检查设备的兼容性和测试结果。

bounds

窗口大小

三、调用

package com.example.demoblog.ui.activity

import android.content.Context
import android.graphics.Point
import android.os.Build
import android.os.Bundle
import android.util.DisplayMetrics
import android.view.WindowInsets
import com.example.demoblog.app.base.BaseActivity1
import com.example.demoblog.databinding.ActivityMainBinding
import com.example.demoblog.viewmodel.state.MainViewModel


class MainActivity : BaseActivity1<MainViewModel, ActivityMainBinding>() {

    private lateinit var binding: ActivityMainBinding

    override fun initView(savedInstanceState: Bundle?) {


        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {

            // 获取当前窗口的度量信息
            val windowMetrics = windowManager.currentWindowMetrics

            //窗口矩阵(窗口大小)
            val windowBounds = windowMetrics.bounds
            val windowWidth = windowBounds.width()
            val windowHeight = windowBounds.height()

            //可见区域
            val insetsIgnoringVisibility =
                windowMetrics.windowInsets.getInsetsIgnoringVisibility(WindowInsets.Type.statusBars())
            val visibleWidth: Int =
                windowWidth - insetsIgnoringVisibility.left - insetsIgnoringVisibility.right
            val visibleHeight: Int =
                windowHeight - insetsIgnoringVisibility.top - insetsIgnoringVisibility.bottom

            //getInsetsIgnoringVisibility 方法测试:
            //height 2245 -> systemBars
            //height 2352 -> navigationBars
            //height 2293 -> statusBars
            //通过上面三个部分得出 navigationBars = 2293 - 2245 = 48,statusBars = 2352 - 2245 = 107
            //这与直接获取状态栏的方法getStatusBarHeight对应

            // 获取屏幕的密度
            val displayMetrics = DisplayMetrics()
            windowManager.defaultDisplay.getMetrics(displayMetrics)
            val screenDensity = displayMetrics.density

            // 打印窗口度量信息
            println("================================R+")
            println("Window Bounds: $windowBounds")
            println("Screen Size: $windowWidth x $windowHeight")
            println("Visible Area: $visibleWidth x $visibleHeight")
            println("Screen Density: $screenDensity")
        } else {

            //获取屏幕和可见窗口大小的方法,第一种
            val display = windowManager.defaultDisplay

            // 创建 Point 对象
            val point = Point()

            // 获取实际的物理尺寸(包含状态栏和导航栏高度)
            display.getRealSize(point)
            val screenWidthPixels = point.x
            val screenHeightPixels = point.y

            // 获取窗口可用的尺寸(不包含状态栏和导航栏)
            display.getSize(point)
            val windowWidthPixels = point.x
            val windowHeightPixels = point.y

            // 打印窗口度量信息
            println("================================R-")
            println("Screen Size: $screenWidthPixels x $screenHeightPixels")
            println("Visible Area: $windowWidthPixels x $windowHeightPixels")


            //获取屏幕和可见窗口大小的方法,第二种
            val displayMetrics = DisplayMetrics()

            // 获取实际的物理尺寸(包含状态栏和导航栏高度)
            display.getRealMetrics(displayMetrics)
            val screenWidthPixels2 = displayMetrics.widthPixels
            val screenHeightPixels2 = displayMetrics.heightPixels

            // 获取窗口可用的尺寸(不包含状态栏和导航栏)
            display.getMetrics(displayMetrics)
            val windowWidthPixels2 = displayMetrics.widthPixels
            val windowHeightPixels2 = displayMetrics.heightPixels

            val screenDensity = displayMetrics.density
            // 打印窗口度量信息
            println("================================R-")
            println("Screen Size: $screenWidthPixels2 x $screenHeightPixels2")
            println("Visible Area: $windowWidthPixels2 x $windowHeightPixels2")
            println("Screen Density: $screenDensity")
        }

        println("======")
        println("getStatusBarHeight=${getStatusBarHeight(this)}")
        println("getNavigationBarHeight=${getNavigationBarHeight(this)}")

    }

    /**
     * 获取状态栏高度
     *
     * @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)
    }

}
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐