Windows微信DPI適配

一、背景

隨著近些年屏幕設備的不斷發展,各種顯示設備的解析度也越來越高,在尺寸保持基本不變的情況下,解析度越高,設備的DPI也越高,清晰度也就越高。高DPI的設備給我們提供了更精細的畫質,然而Windows上的大多數應用並沒有適配高DPI的顯示器,導致應用在這些設備顯示模糊,體驗非常差。

為了讓應用在高DPI的設備上依然顯示清晰,我們就需要對高DPI的設備進行適配。

二、基礎概念

2.1 DPI是什麼

DPI是Dots Per Inch的縮寫,表示顯示設備在每英寸上有多少個像素點。在開發過程中,我們會接觸到兩個DPI的概念:面板DPI和OS DPI。

面板DPI是設備真實的DPI,是一個固定的物理屬性。

OS DPI是操作系統根據面板DPI校準后的一個標準化的DPI值。適配過程中所使用的DPI都是指的OS DPI。Windows平台中標準的OS DPI值一般有96 、120、144、192這四個值,用戶可以在系統的控制面板里進行修改。

2.2 DPI和縮放比例的關係

現在我們已經知道DPI是個什麼了,那麼DPI又是怎樣影響我們應用程序的界面的呢?

假設現在有兩台顯示器,顯示器A:22寸,解析度1920*1080,DPI=100。顯示器B:22寸,解析度3840*2160,DPI=200。顯示器B的DPI是顯示器A的2倍。現在顯示一張解析度為1920*1080的圖片,在顯示器A上,得到的效果如下:Windows微信DPI適配

圖片是剛好撐滿了整個顯示器。

在顯示器B上,得到的效果如下:Windows微信DPI適配

同樣的圖片,在顯示器B上只佔用了1/4面積的屏幕。

B的DPI是A的2倍,在默認處理下,實際的顯示效果是:圖片在A上顯示的寬和高分別是B上的2倍。這個時候用戶肯定不開心了,選擇解析度更高(通常也是DPI更高)的設備是為了顯示更細膩而現在卻是顯示的內容越來越小。為了讓高DPI上實現更好的顯示效果。這個時候就我們在需要在高DPI的設備上放大我們的界面元素,在低DPI設備上縮小我們的界面元素,使用戶在不同的設備上看到的內容的大小基本一致。

上面例子中我們是使用面板DPI來舉的例子。面板DPI是不變的,OS DPI是可以通過設置改變的,並且應用中獲取到的DPI是OS DPI。那麼用戶就可以通過改變OS DPI來實現縮放系統界面元素和應用界面。

Windows以DPI為96作為100%大小的基準。提供了120、144、192四個標準的DPI值。其各自對應了一個縮放比例。

Windows微信DPI適配

2.3 有效解析度

對於一個顯示器,其物理解析度和面板DPI是固定的,OS DPI決定了界面的縮放比例。DPI增大,應用界面是增大的,相反顯示器的邏輯解析度是在減小的。例如,3840*1920 DPI=192的顯示器,對於應用而言,屏幕上的兩個像素點變成了原來的一個像素點,所以其解析度相當於變成了1920*1080,這個解析度就稱之為有效解析度。

2.4 DPI Virtualization

對於Windows Vista之後的系統,當Windows檢測到的程序不支持DPI縮放時(即非DPI Aware的程序),DWM會直接放大窗口。虛擬化之後的應用由於直接對像素進行縮放,所以界面會變得模糊。Windows微信DPI適配

2.5 應用DPI感知級別

前面提到了DWM會使用虛擬化技術來默認處理那些為適配DPI的應用,那麼系統怎麼判斷這個應用有沒有適配呢?系統是通過應用設置的DPI感知級別來判斷應用是否適配了DPI。Windows微信DPI適配

三、適配步驟

了解了適配相關的基礎概念之後,接下來開始對應用進行適配了。

在未對DPI進行適配之前,窗口、控制項構建的大致過程如下:Windows微信DPI適配

適配的主要工作包括資源的適配和尺寸調整兩個方面,調整之後的流程如下:

Windows微信DPI適配

3.1 聲明DPI感知級別

適配應用,首先我們需要聲明我們的應用是DPI感知級別的。聲明DPI感知有兩種方法,一種方法是通過Manifest進行聲明,

<assembly ...> <asmv3:application> <asmv3:windowsSettings ...> <dpiAware>true</dpiAware> </asmv3:windowsSettings> </asmv3:application> </assembly>

通過設置dpiAware為true就聲明應用支持DPI縮放。如果想要支持Per Monitor模式的DPI縮放,則需要設置dpiAware值為true/PM。這種方式是官方推薦的方式。需要注意的是,如果程序是一個DLL,則Manifest中的設置會被忽略。

另一種方式是通過SetProcessDPIAware函數進行設置,官方不推薦使用此方式,在兩種特殊情況下可以優先考慮這種方式:1.應用本身是一個DLL。2.應用需要按照OS支持不同級別的適配。一般來說,優先考慮使用第一種方式。

3.2 確定DPI縮放因子

在控制項和窗口創建之前需要先確定DPI縮放因子。

3.2.1 GetDeviceCaps

通過GetDeviceCaps可以獲取到水平和垂直方向的DPI值,得到了DPI值,還需要明確支持的DPI縮放範圍。Windows中,目前有96、120、144、192四種標準的DPI,當然用戶也可以設置為其它DPI大小。實際適配時,支持96、120、144、192四種標準DPI即可,其它DPI則可以取相近的標準DPI。最後根據DPI就可以確定水平和垂直方向的縮放因子。

3.2.2 GetSystemMetrics

通過GetSystemMetrics可以得到顯示器的解析度,再根據前面得到的DPI值,就可以確定當前的有有效解析度。如果有效解析度過低(Windows推薦的有效解析度不低於1024*720),可能會導致界面顯示不全,這個時候就需要適當的縮小縮放因子或者提示用戶。

3.3 資源適配

一般來說,DPI不同,界面的大小不同,需要的資源也就不同。

3.3.1 資源目錄

每一種DPI都有一個對應的資源目錄,資源在這些目錄下採用相同的相對路徑。例如一張test.png圖片分辨適配1x(96 DPI)和1.5x(144 DPI)時,[email protected]/xxxx/test.png。

3.3.2 圖片資源

對於圖片資源,優先使用對應目錄下的資源。如果在對應目錄下沒有找到資源,則可以使用最其他DPI目錄下的資源。使用其他DPI目錄的圖片資源時,在使用之前還需要先進行縮放處理,縮放的比例由相關的兩個DPI的比值決定,以查找120 DPI下test.png為例。具體流程如下:Windows微信DPI適配3.3.3 xml等構建UI的資源

一般來說,除非想在不同的DPI、有效解析度下採用不同的布局方式,建議只使用一套xml資源。這樣可以減少適配的工作量,同時避免維護多套xml帶來的麻煩。

3.4 窗口和控制項縮放

窗口和控制項的縮放是DPI適配的主要工作。

3.4.1 xml適配

Windows版微信中,窗口和控制項構建支持使用xml進行配置,對於xml構建的窗口和布局適配起來比較簡單,工作量也比較小,只需要在讀取xml的時候直接與縮放因子相乘就行了。為了使xml更靈活,xml中最好支持使用不同的單位進行配置。類似px,pt,dp這樣的單位。

3.4.2 代碼適配

對於代碼中構建的窗口和布局,適配的工作量就要大一些了。這一部分主要工作就是將原先代碼中動態設計算的尺寸與縮放因子相乘得到縮放后的尺寸。

對於代碼中使用的常量尺寸,在定義的時候可以考慮#define而不是const常量。例如對於一個窗口寬度WND_WIDTH

#define WND_WIDTH 100 * dpi_x

而不是用

const int WND_WIDTH = 100 * dpi_x;

這樣做的優點是如果應用考慮做到Per-Monitor級別的適配或者需要動態切換縮放比例時,這部分的代碼可以直接使用而不需要再做修改了。

3.4.3 字體適配

Windows微信使用CreateFontIndirect創建字體,在創建的時候,只需要對lfHeight進行縮放就可以了。

3.4 測試

在開發的時候,一般都需要及時觀察到適配的效果,這裡簡單的做法就是強制設定縮放因子為我們的需要測試的值就可以了。但是對於最終的顯示效果還需要通過更改系統設置的縮放比例后觀察的效果為準。

四、總結

對於Windows平台而言,未來高清設備一定會越來越多,所以適配DPI變得越來越重要。通過上面的步驟,能夠滿足大多數應用對於DPI適配的需求,但對於需要做到Per-Monitor級別的適配的應用,就還需要更多的工作以完成適配。

五、參考文檔

https://msdn.microsoft.com/en-us/library/dn469266(v=vs.85).aspx#pixelated_text

未经允许不得转载:Feenix第四色色 » Windows微信DPI適配

赞 (0)
分享到:更多 ()

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址