使用 Qt 来开发 Android 应用,也需要适配不同移动设备,适配多种多样的屏幕和分辨率。这次我们大概来讲一下如何使用 Qt 提供的机制来创建可伸缩的界面。
DPI
必须要解释一下 DPI 。
DPI , dot per inch ,即每英寸包含的点数。还有一个概念是 PPI ,即每英寸包含的像素数。
这个值越大,像素密度越大,小尺寸的屏幕就可以有大分辨率。比如有的 Android 手机, 3.7 吋屏幕就能提供 960x540 的分辨率,而有的手机, 5 吋屏幕却提供 800x480 的分辨率。这两种不同屏幕的尺寸和分辨率的手机,5 吋屏看起来会有颗粒感,而 3.7 吋看起来则非常细腻。这就是像素密度带来的差别。
DPI 对界面的影响是酱紫的:同样分辨率(按像素来说)的图片,在 DPI 越大的屏幕上,看起来就越小。
三类可伸缩元素
一个 Qt 移动应用,大概有三类可伸缩 UI 元素:
- 文字
- 图片
- 背景
我们分别来看一下。
文字
对于文字来讲,我们只需要设置特定的文本显示和输入控件所使用的字体(QFont)的 pointSize 即可。像 QLabel 、 QPushButton 、 QLineEdit 等等都适用这种方式。
QFont 的大小有两种表达方式: pixelSize 和 pointSize 。 pointSize 会根据应用所在的设备的 DPI 来调整字体,使得在不同 DPI 的设备上看起来效果一致。
Qt 里面可以单独改变一个 Widget 使用的字体,也可以通过 QApplication 来提供全局的字体,这样那些没有专门设置的 Widget ,就会使用全局的字体。
图片
前面我们说了,同样分辨率的图片,屏幕 DPI 越大,人眼看过去,就觉得越小。
Qt 可以处理这种情况,我们以 QPixmap 为例来说明。
QPixmap 有两个方法:
- void setDevicePixelRatio(qreal scaleFactor)
- qreal QPixmap::devicePixelRatio() const
这两个方法操作一个叫作 device pixel ratio 的属性,这个属性指定了设备相关的像素和设备无关的像素之间的换算比率。我们可以通过调整它来改变一个图片在手机屏幕上看起来的效果。
QImage 类同样有这两个方法。大家可以查阅 Qt 帮助来看 API 的细节。
那如何获取一个设备的 devicePixelRation 呢?
QScreen 有个方法可以返回这个值:qreal QScreen::devicePixelRatio() const
QGuiApplication 、 QWindow 这两个类也有同名的方法。
我们也可以自己计算,使用 QScreen 的 logicalDotsPerInch() 方法结合一个常见的 DPI (比如 72)来计算,下面是示例代码:
float SizeUtil::dpiFactor()
{
QScreen *screen = qApp->primaryScreen();
return 72 / screen->logicalDotsPerInch();
}
我在后面的示例中用了上面的方法。
要说明的是,Qt 的内建控件在使用 QPixmap 和 QImage 时,会结合 devicePixelRation 来决定这个控件的大小,我们的示例里使用 QLabel 来显示图片。
背景
背景要么是某种颜色,要么是一张图片。当使用图片做背景时,面临拉伸问题。 Android 使用 9patch 图片来解决这个问题, Qt 也提供了类似的东西:border-image 。
在基于 Qt Widgets 的应用里,我们可以通过 qss 来设置 border-image ,进而构造可伸缩的背景。
上图是 Qt 帮助里的,四条线把一张图片切成了 9 份,使用时,可以保持四个角不变,其它部分通过拉伸或平铺填充来适应界面空间大小。
好啦,基本的背景就这么多了,我们来看一个简单的例子。
可伸缩界面示例
我们先看效果后看代码。
效果图
下图是 PC 上的运行效果:
下图是手机上的效果,此时图片没有