Qt on Android:怎樣適應不同的螢幕尺寸
使用 Qt 開發的 Android 應用,怎樣適應 Android 智能手機各種各樣的螢幕尺寸?
說到螢幕尺寸,從 2.8 吋到 8.9 吋的手機螢幕都有,這對程式猿們來講痛苦可不只一點。 Android 項目本身已經考慮了這個問題,資源檔,比標,都有 ldpi / mdpi / hdpi / xhdpi 等等版本, Android 架構會根據螢幕大小自動選擇相應的表徵圖,這樣在不同尺寸的螢幕上,應用看起來就差不多了。
那 Qt 應用呢?其實不大用得上 Android 的這種機制(惟有 App Icon 可以搭便車),一切都得自己處理了。那怎麼處理呢?
首先要理解 DPI ,然後是字型大小。
DPI 與字型大小
DPI , dot per inch ,即每英寸包含的點數。還有一個概念是 PPI ,即每英寸包含的像素數。一般我們用 DPI 就夠了,對於專業人士處理超高 DPI 的情境,使用 PPI 可能更精確一些。在 Qt 中,只有 DPI ,所以我們單說它吧。
這個值越大,像素密度越大,小尺寸的螢幕就可以有大解析度。比如有的 Android 手機, 3.7 吋螢幕就能提供 960x540 的解析度,而有的手機, 5 吋螢幕卻提供 800x480 的解析度。這兩種不同螢幕的尺寸和解析度的手機,5 吋屏看起來會有顆粒感,而 3.7 吋看起來則非常細膩。這就是像素密度帶來的差別。
有的螢幕,橫向的 DPI 和縱向的 DPI 不一樣,即像素點不是正方形,這就更複雜了……
我們在寫應用時,理想的情況是:應當根據 DPI + 螢幕解析度來設定介面元素的大小。
QScreen 類
在 Qt 中, QScreen 類可以擷取到 DPI 相關的資訊。
QScreen 的 physicalDotsPerInch / physicalDotsPerInchX / physicalDotsPerInchY 這一組屬性工作表示物理 DPI 。 logicalDotsPerInch / logicalDotsPerInchX / logicalDotsPerInchY 這一組屬性工作表示邏輯 DPI , Qt 使用它來計算字型大小,我們可以用它將字型的 pointSize 轉換為 pixelSize 。下面咱們就來說它。
logicalDotsPerInch 是一個 X 、 Y 的簡單平均值,多數情況下就夠用了,當然如果你有極致追求,請問道於 logicalDotsPerInchX 和 logicalDotsPerInchY 。
QFont 類
QFont 代表字型,字型的大小有兩種表示方式: pixelSize 和 pointSize 。即像素大小和點陣大小。如果你使用像素大小來表示字型,那字型將不受 DPI 的影響,在電腦上你可以調整顯示器的 DPI 來觀察介面的變化。但這不適用於移動情境中適配多樣化螢幕尺寸的要求。在針對 Android 裝置開發時,我們應當使用字型的 pointSize ,這也是 Qt 應用的預設處理方式。
廢話了不是,預設就是 pointSize ,還囉嗦個甚!
非也非也!且往下看。
Qt 中的控制項
Qt 中有 QLabel / QPushButton / QListWidget / QTabelWidget 等等可以在 Android 裝置上使用的控制項,它們可以用來顯示文本。你找來一堆不同尺寸螢幕的手機,使用 QFont 的 setPointSize() 方法調整一下字型的點陣大小,權衡一下效果,就可以決定你的應用的字型尺寸如何設定了。
但還有非文本的情境,比如你是圖片按鈕,那怎麼辦呢?
我的答案是:根據字型的點陣大小計算出像素大小,然後拿這個來調整非文本控制項的大小。這樣子介面上的文本元素和圖片等非文本元素才可以匹配起來。
從 pointSize 到 pixelSize 的計算公式: pixelSize = DPI * pointSize/72 。
Qt 應用如何使用 DPI
看一個程式碼片段:
int main(int argc, char **argv){ QApplication a(argc, argv); ... QScreen *screen = a.primaryScreen(); QFont f = a.font(); int pixelSize = (f.pointSize() * screen->logicalDotsPerInch()) / 72; /* f.setPointSize(25); a.setFont(f); int newPixelSize = (f.pointSize() * screen->logicalDotsPerInch()) / 72; */ ...}
其實很簡單,只要設定了 QApplication 的 字型,你應用的所有介面元素的字型大小都會變。如果你想單獨設定某個 Widget 的字型,可以針對它調用 setFont() 方法。
上面的代碼還示範了從 pointSize 到 pixelSize 的換算,一旦你得到了合適的 pixelSize ,就可以以它為基礎來設定非文本介面元素的尺寸。
Qt 擷取螢幕解析度
前面我們說最好結合解析度和 DPI ,一起來調整介面元素。 DPI 的使用已經簡單介紹過了,剩解析度了。
QScreen 類的 size 屬性可以返回螢幕的像素尺寸, availableSize 可以返回應用能夠使用的尺寸。兩者的區別是, availableSize 移除了視窗管理器佔用的尺寸(在電腦上就是工作列, Android 手機上是狀態列之類的地區)。
下面是一個簡單的範例程式碼:
#ifdef ANDROID QSize iconSize(32, 32); ... QScreen *screen = qApp->primaryScreen(); QFont f = qApp->font(); int pixelSize = (f.pointSize() * screen->logicalDotsPerInch()) / 72; QSize screenSize = screen->size(); if(screenSize.width() > 960 || screenSize.height() > 960) { iconSize *= ((qreal)pixelSize) / 20; }#endif
我們知道該如何設定 Qt on Android 應用來適配多樣化的螢幕尺寸,但你的應用運行後是什麼效果,就看你如何綜合使用前面介紹的這些內容了……
本系列的其它文章:
- Qt on Android:圖文詳解Hello World全過程
- Windows下Qt 5.2 for Android開發入門
- Qt for Android 部署流程分析
- Qt on Android:將Qt調試資訊輸出到logcat中
- Qt on Android: Qt 5.3.0 發布,針對 Android 改進說明
- Qt on Android Episode 1(翻譯)
- Qt on Android Episode 2(翻譯)
- Qt on Android Episode 3(翻譯)
- Qt on Android Episode 4(翻譯)
- Qt for Android 編譯純C工程
- Windows下Qt for Android 編譯安卓C語言可執行程式
- Qt on Android: Android SDK安裝
- Qt on Android: http下載與Json解析
- Qt on Android 之設定應用程式名稱為中文
- Qt on Android:讓 Qt Widgets 和 Qt Quick 應用全螢幕顯示