窗口大小类别

窗口大小类别是一组主观的视口断点 设计、开发和测试响应式/自适应布局。断点平衡 让布局简单明了,可以灵活地针对独特情形优化应用。

窗口大小类别将可供应用使用的显示区域分类为 compactmediumexpanded。可用宽度和高度进行分类 因此在任何时间点,应用都有两个窗口大小 类,一个用于宽度,一个用于高度。可用宽度通常更大 由于垂直滚动的普遍存在,“高度”比可用高度重要, 宽度窗口大小类别很可能与应用的界面更相关。

图 1. 基于宽度的窗口大小类别的表示。
图 2. 基于高度的窗口大小类别图示。

如图所示,这些断点可让你继续思考 从设备和配置角度考虑布局每个大小类别划分点代表了典型设备场景的大多数情况,当您考虑基于划分点的布局设计时,这可能是一个有用的参考框架。

大小类别 划分点 设备表示
较小的宽度 宽度 < 600dp 99.96% 的手机处于竖屏模式
中等宽度 600dp ≤ 宽度 < 840dp 93.73% 的平板电脑处于竖屏模式,

大多数展开后的纵向内屏

较大宽度 宽度 ≥ 840dp 97.22% 的平板电脑处于横屏模式,

大多数展开后的横向大型内部显示屏

较小的高度 高度 < 480dp 99.78% 的手机处于横屏模式
中等高度 480dp ≤ 高度 < 900dp 96.56% 的平板电脑处于横屏模式,

97.59% 的手机处于竖屏模式

展开高度 高度 ≥ 900dp 94.25% 的平板电脑处于竖屏模式

虽然将大小类别可视化为实体设备可能很有用,但窗口大小 类并非由设备屏幕的尺寸明确决定。窗户 大小类不适用于 isTablet 类型的逻辑。相反,窗口 大小类别由应用可用的窗口大小决定 无论在哪种类型的设备上运行应用 影响:

  • 实体设备不能保证特定的窗口大小类别。通过 应用的可用屏幕空间可能不同于 导致这种情况的原因有很多在移动设备上,分屏模式可以 用于在两个应用之间划分屏幕。在 ChromeOS 上,Android 应用 显示在可任意调整大小的自由式窗口中。 可折叠设备可以分别访问两个不同尺寸的屏幕 展示您的应用。

  • 窗口大小类别在应用的整个生命周期内可能会发生变化。 当应用运行时,设备屏幕方向会发生变化、多任务处理以及 折叠/展开可能会改变可用的屏幕空间大小。作为 因此,窗口大小类别是动态的,应用的界面应调整 。

窗口大小类别映射到 Material Design 布局 指南。 使用窗口大小类别做出高级应用布局决策, 例如,决定是否使用特定的规范布局来利用 增加屏幕空间

您可以使用 Jetpack WindowManager 库提供的 WindowSizeClass#compute() 函数来计算当前的 WindowSizeClass。以下示例展示了如何计算窗口大小类别,并在窗口大小类别发生变化时接收更新:

Kotlin

class MainActivity : Activity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // ...

        // Replace with a known container that you can safely add a
        // view to where the view won't affect the layout and the view
        // won't be replaced.
        val container: ViewGroup = binding.container

        // Add a utility view to the container to hook into
        // View.onConfigurationChanged(). This is required for all
        // activities, even those that don't handle configuration
        // changes. You can't use Activity.onConfigurationChanged(),
        // since there are situations where that won't be called when
        // the configuration changes. View.onConfigurationChanged() is
        // called in those scenarios.
        container.addView(object : View(this) {
            override fun onConfigurationChanged(newConfig: Configuration?) {
                super.onConfigurationChanged(newConfig)
                computeWindowSizeClasses()
            }
        })

        computeWindowSizeClasses()
    }

    private fun computeWindowSizeClasses() {
        val metrics = WindowMetricsCalculator.getOrCreate().computeCurrentWindowMetrics(this)
        val width = metrics.bounds.width()
        val height = metrics.bounds.height()
        val density = resources.displayMetrics.density
        val windowSizeClass = WindowSizeClass.compute(width/density, height/density)
        // COMPACT, MEDIUM, or EXPANDED
        val widthWindowSizeClass = windowSizeClass.windowWidthSizeClass
        // COMPACT, MEDIUM, or EXPANDED
        val heightWindowSizeClass = windowSizeClass.windowHeightSizeClass

        // Use widthWindowSizeClass and heightWindowSizeClass.
    }
}

Java

public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // ...

        // Replace with a known container that you can safely add a
        // view to where the view won't affect the layout and the view
        // won't be replaced.
        ViewGroup container = binding.container;

        // Add a utility view to the container to hook into
        // View.onConfigurationChanged(). This is required for all
        // activities, even those that don't handle configuration
        // changes. You can't use Activity.onConfigurationChanged(),
        // since there are situations where that won't be called when
        // the configuration changes. View.onConfigurationChanged() is
        // called in those scenarios.
        container.addView(new View(this) {
            @Override
            protected void onConfigurationChanged(Configuration newConfig) {
                super.onConfigurationChanged(newConfig);
                computeWindowSizeClasses();
            }
        });

        computeWindowSizeClasses();
    }

    private void computeWindowSizeClasses() {
        WindowMetrics metrics = WindowMetricsCalculator.getOrCreate()
                .computeCurrentWindowMetrics(this);

        int width = metrics.getBounds().width
        int height = metrics.getBounds().height()
        float density = getResources().getDisplayMetrics().density;
        WindowSizeClass windowSizeClass = WindowSizeClass.compute(width/density, height/density)
        // COMPACT, MEDIUM, or EXPANDED
        WindowWidthSizeClass widthWindowSizeClass = windowSizeClass.getWindowWidthSizeClass()
        // COMPACT, MEDIUM, or EXPANDED
        WindowHeightSizeClass heightWindowSizeClass = windowSizeClass.getWindowHeightSizeClass()

        // Use widthWindowSizeClass and heightWindowSizeClass.
    }
}

测试窗口大小类别

在更改布局时,请测试所有窗口大小的布局行为, 尤其是在较小、中等和较大断点宽度下。

如果您已有适用于较小屏幕的现有布局,请先优化布局 因为此尺寸类别提供的空间最大 了解更多内容和界面变化。然后确定适合的布局 中等宽度大小类别请考虑添加专用布局

后续步骤

详细了解如何使用窗口大小类别创建响应式/自适应式 请参阅以下内容:

如需详细了解如何让应用在所有设备上以及所有屏幕尺寸下都表现出色, 请参阅: