自适应缩放(分辨率独立性)

本指南概述了 Corona 中的**虚拟像素**,并解释了如何使用**自适应**缩放使其行为类似于原生 iOS/Android 虚拟像素。

简单内容缩放

Corona 提供了自己的虚拟像素方案,称为**内容缩放**。这允许开发者指定一组通用的屏幕坐标,而 Corona 会根据设备自动缩放文本、矢量对象和图像到不同的分辨率。

实际上,有多种方法可以实现内容缩放。最简单的方法是选择一个单一的固定大小的虚拟屏幕,如下所示:

  1. 以虚拟像素定义内容区域的**宽度**和**高度**(Corona 内容单位)。这隐式定义了要围绕其进行编码的虚拟坐标系。

  2. 指定一个**缩放**模式,例如 "letterbox""zoomEven" —— 这决定了 Corona 如何填充屏幕。

  3. 如果使用 "letterbox" 模式,请针对虚拟屏幕和实际设备的纵横比不同时出现的空白信箱区域进行设计 —— 这些区域类似于电视节目以信箱模式显示时的黑条,不同之处在于,在 Corona 中,这些区域可以(并且**应该**)绘制视觉内容。或者,如果使用 "zoomEven" 模式,请理解当纵横比不同时,某些视觉内容可能会从屏幕上溢出。

实际上,一个简单的 config.lua 文件可能包含如下值:

application =
{
    content =
    {
        width = 320,
        height = 480,
        scale = "letterbox",
    }
}

在本指南中,此方法将被称为**简单内容缩放**,之所以这样命名,是因为固定大小的屏幕简化了开发。固定的虚拟内容宽度和高度,由 display.contentWidthdisplay.contentHeight 表示,使应用程序的编码更容易,因为它提供了一个静态的内容大小来进行设计。

有关内容缩放及其配置方式的更多详细信息,请参阅项目配置指南。

简单缩放的局限性

虽然简单内容缩放在大多数情况下都能很好地工作,但它并非万能的。在某些应用程序中,尤其是以 UI 为中心的应用程序中,它存在各种缺点,包括:

自适应内容缩放

鉴于简单内容缩放的各种缺点,尤其是在以 UI 为中心的应用程序中,如果界面元素在所有设备上的大小大致相同,那将很方便。幸运的是,Corona 的**自适应**内容缩放解决了这个问题,同时仍然提供了良好的像素缩放并消除了信箱区域。

要设置自适应内容缩放,只需将 config.lua 中的 scale 键设置为 "adaptive" 即可。

application =
{
    content =
    {
        scale = "adaptive",
    }
}
注意

由于自适应缩放会按照下一节所述计算内容区域大小,因此在使用 "adaptive" 缩放模式时**无需**定义 widthheight 值。

核心原则

对于自适应缩放,Corona 使用启发式方法来确定适当的内容宽度和高度。主要目标有三个:

  1. 虚拟屏幕的纵横比应与实际设备屏幕匹配,这意味着没有信箱区域。

  2. 首选像素缩放比例应尽可能为整数(或**简单分数**)。

  3. 虚拟像素密度在不同设备上应大致相同。

对于 iOS,这是通过将内容宽度和高度设置为与设备以 iOS 点为单位的宽度和高度相匹配来实现的。这很有效,因为 iOS 点的物理尺寸大致相同。

对于 Android,内容宽度和高度设置为匹配**dp**(设备独立像素)单位,使用大致的 PPI(每英寸像素数)hdpixhdpi 等)以及实际屏幕像素宽度/高度来计算内容屏幕大小。这同样有效,因为 Android **dp** 值的物理长度大致相同。

只要允许虚拟屏幕大小更改,就会存在权衡,并且复杂性会略有增加。具体来说,代码应该知道内容宽度和高度可以根据设备而变化。因此,与其对某些界面元素使用静态宽度和高度值,不如通过 display.contentWidthdisplay.contentHeight 以及围绕这些属性的各种计算**动态**定义这些值,例如display.contentWidth * 0.5将对象的宽度设置为屏幕宽度的一半。这些属性也应该用于定位,例如将对象的**y** 位置设置为 display.contentHeight,将其垂直中心点定位在屏幕底部。

简单缩放 vs. 自适应缩放

简单内容缩放和自适应内容缩放之间的区别本质上在于:

  • 在简单缩放场景中,内容的**视觉大小**会被缩放。因此,在更大的屏幕上,对象实际上会以标尺长度(例如英寸或厘米)变得更大。

  • 在自适应缩放场景中,内容的视觉大小在不同屏幕尺寸上大致相等,这意味着更大设备上有更多可用屏幕空间。

理解差异的另一种方法是检查像素缩放比例会发生什么变化。使用简单内容缩放,像素缩放比例在不同设备上有所不同,但在自适应缩放中保持不变。考虑以下比较:

  • 在简单缩放场景中,假设内容宽度设置为 320。在屏幕分辨率宽度为 750 的 iPhone 7 上,像素缩放比例约为2.3 (750/320)750 / 320 = ~2.34,这意味着一个虚拟像素对应约 2.3 个实际像素。在更大的 iPhone 7 Plus 上,屏幕分辨率宽度为 1242,像素缩放比例变为约3.9 (1242/320).

  • 1242 / 320 = ~3.88使用自适应内容缩放,两个设备上的像素缩放比例均为 2,因为 Apple 设计了每个设备的点宽度和高度,使计算结果有效:iPhone 7 上的点宽度为 375,像素宽度为 750,而 iPhone 7 Plus 上的点宽度为 621,像素宽度为 1242。

Retina 图像

自适应缩放还会影响 Retina/HD 图像选择的缩放阈值的选择(有关详细信息,请参阅动态图像选择)。.

在简单缩放场景中,可能需要高达@4x 后缀的图像,因为内容有时需要缩放至 400% 或更高,尤其是在 Retina/HD 平板电脑上。然而,在自适应缩放场景中,通常只需包含 @2x@3x 后缀的图像版本即可。

在为 config.luaimageSuffix 表选择实际阈值时,@2x@3x 后缀的@3x 图像的缩放阈值分别为 2.03.0 似乎是合乎逻辑的,如:

application =
{
    content =
    {
        scale = "adaptive",
        imageSuffix =
        {
            ["@2x"] = 2.0,
            ["@3x"] = 3.0,
        },
    }
}

但是,有两个特定原因导致阈值应该降低:

  1. 在 Android 上,hdpi 设备的分数比例为 1.5 倍。在这种情况下,应通过将关联阈值降低到 1.5 来选择 @2x 图像。

  2. iPhone 7 Plus 是一款像素缩放比例有点奇怪的设备。在这里,基于 UIKit 的应用程序会被误导,认为缩放比例是 3 倍,但实际上在缩小后实际上是 2.6 倍;对于基于 OpenGL 的基于 Metal 的游戏,它直接是 2.6 倍。在这种情况下,应该使用 @3x 图像,否则将选择 @2x 图像并放大,这可能看起来不太理想。这可以通过将关联阈值降低到 2.5 来实现。

考虑到这些因素,**自适应** config.lua 应包含如下阈值:

application =
{
    content =
    {
        scale = "adaptive",
        imageSuffix =
        {
            ["@2x"] = 1.5,
            ["@3x"] = 2.5,
        },
    }
}