本文参考文章:In Pixels we trust, Scalable UIs In QML part 2.,感谢原文作者的贡献。
上一篇,我们谈到了扩展的难度在于扩展当前我们已经应用于移动和嵌入式设备的 PPI 范围。我们还提到了避免这个问题的最常见的方法是通过提供几种不同分辨率下的图像资源来帮助缓解这个问题。
它是如何工作的?我们又如何在 QML 中进行实现呢?更重要的是它是否存在问题?这是最好的解决方案么?它权衡了哪些利弊?
图标
图标是一个比较容易入手的点,图标在移动设备诞生之前就被我们进行缩放,这与我们现在在移动设备上进行的缩放非常类似。平台的图标尺寸通常是2的倍数,它一般是像16x16, 24×24, 32×32, 48×48, 64×64, 96×96, 128×128,172×172, 256×256, 512×152… 这样类似。所有这些尺寸的原因有很多,包括营销、具体使用、类型、可点击区域和可见性等。但你可能会问,如何会这么多,我们怎么不只是使用一个大小?
为了回答这个问题,我们首先需要了解像素和缩放效果。
什么是像素?
英文为Pixel,又叫Picture element。数字图象是由按一定间隔排列的亮度不同的像点构成的,形成像点的单位称“像素”,也就是说,组成图象的最小单位是像素,像素是图象的最小因素。从计算机技术的角度来解释,像素是硬件和软件所能控制的最小单位。它指显示屏的画面上表示出来的最小单位,不是图画上的最小单位。像素是在影像感应器上将光信号转变成电信号的基本工作单位,以 CMOS 感应器的像素为例,它包含了一个光电二极管,用来产生与入射光成比例的电荷,同时它也包含了其他一些电子元件,以提供缓存转换和复位功能。当每个像素上的电容所积累的电荷达到一定数量并被传送给信号放大器再通过数模转换之后,所拍摄影像的原始信号才得以真正显现,而具有这些全部功能的器件才能称为是一个真正的影像感应器。比如,一台数码相机的最高分辨率为3264×2448,意味着它拥有的影像感应器会有7990272个像素点。该段文字参考什么是像素。
缩放是如何实现的?
缩放可以通过多个智能或非智能算法完成,但通常是新渲染网格中像素插值的结果。 结果是当像素被拉伸时,它被分布在新的像素网格上。
关于图标的一些事项
图标是使用像素网格充分发挥其潜力的特殊图像。我们仍然以像素绘制图标,即使它们实际是在矢量绘图应用程序中完成的。我们仍然将我们的矢量与虚拟渲染网格对齐,我们这样做可以最大限度地提高对比度和锐度,因此图标往往会大量的使用垂直和水平的对比度。
缩放图标会导致模糊图像,因为这些像素对比度在内插过程中会变得模糊,如果对比线在主要的16×16网格线上完成,则只能处理多个值。即使在那里我们失去了有意义的数据,作为1像素宽的对比度成为0.5或0.25的子像素。
因此,当我们进行图像处理时,每个图标都会针对每个尺寸进行重做,我们绝对不会将图标从一个大小缩放到另一个尺寸...
您可以在图像中看到,将图标缩放1像素可能会导致非常模糊的结果。 我的建议是,如果您需要不同尺寸的图标,每英寸不同的像素看起来相同,那么您应该提供多个图像,使用2x和1之间的缩放因子,并重新绘制图标,以利用额外的像素。
Android 期望的图标
再以 Android 平台为例:
为了创建不同密度的图标,您应该遵循五个主要密度(分别为: medium, high, x-high, xx-high, and xxx-high)之间的2:3:4:6:8缩放比例。例如,考虑将启动器图标的大小指定为48×48 dp。 这意味着基准线(MDPI)的 asset 为 48×48 像素,high 密度(HDPI)asset 应为基准线的1.5倍即 72×72 像素,x-high 密度(XHDPI)asset 应为基准线的两倍即 96×96 像素,等等。
按钮和其他 X/Y 独立的可扩展元素
应该以独立于 X/Y 的方式扩展的 UI 元素,如Buttons、GroupBoxes和其他自定义的基于图像的元素。他们如何工作?
在QML中,我们有一个由这些元素构成的组件,例如 BorderImage,它可以将图像分割成 9 部分,所以它可以适当的方式缩放/平铺每一个图像。
BorderImage {
id: scalableElement
source: "./image/Imagebase.png"
width: 100; height: 100
border.left: 25; border.top: 25
border.right: 25; border.bottom: 25
}
上面的代码,通过对 Imagebase.png 的图像指定 25 像素的四个边距,从而达到不缩放图片的四个角,仅仅拉伸这 25 像素边距之外的区域来创建了一个 100X100 像素的元素。
现在的主要问题是什么? 应该有多大? 用什么度量?
如果它在触摸屏上使用,那么它应该足够大,您可以触摸它,而不会导致误触,足够大应该是是7到9毫米之间,这也取决于用户可以容忍度。这个数字粗略地说明你的拇指与触摸屏的接触面的大小。
这意味着我们在这里有两个矛盾的指标,一方面我们有像素,在另一个物理尺寸上,我们仍然以像素表示 QML 代码的值,但是我们需要使这个元素大小符合我们的拇指的大小。
PPI 还是 DPI ?
PPI或DPI是屏幕一英寸的像素数量,我们可以通过多种方法将 PPI 显示给 QML,但是我们希望的是真正的 PPI 而不是逻辑的。如果你是一个“像素狂魔”,你可能需要 PPIx 和 PPIy —— 它们使得像素不再总是真的“正方形”的。
将这个理论应用到之前的代码上,我们可以有如下的代码:
....
property int dpi: Screen.pixelDensity*25.4
....
BorderImage {
id: scalableElement2
source: "./image/Imagebase.png"
width: 1.5*dpi; height: 0.36*dpi
border.left: 25; border.top: 25
border.right: 25; border.bottom: 25
}
该代码展示了我们将使用最常用的方法,ppi 或 dpi作为主要指标。无论我们使用什么屏幕,它都将创建一个1.5英寸长的0.36英寸高的按钮。然而,在多个屏幕上它看起来仍然会不一样,拐角处的曲率可能会随着 PPI 的增长而下降,同时阴影也将变得越来越不可见。所以我们需要引入一个我们为图标准备的类似的解决方案,我们可以使用多个 BaseImage 为多个可能的 PPI 范围。在我的下一篇博客文章中,我将尝试展示如何以不是太丑陋的方式来完成这一目标。我们还将讨论这种方法的局限性……QML 中的缩放(3):BorderImage