之前一直使用的是Material Design的圖標庫,下載下來以后直接放入了對應文件夾,什么尺寸對應什么dpi都沒有仔細研究過。
最近在Toolbar上添加幾個不是MD圖標庫內的圖標時發現,放入的圖標在顯示時有時候感覺被放大了,有時候又顯得模糊。讓我對這個圖標的尺寸和顯示系統產生了好奇,折騰了一番,終於算是基本弄清楚了。
PX、DP和DPI
首先復習一下屏幕像素密度的知識:
- px:像素點
- dpi:像素密度,即每英寸像素數
- dp:屏幕密度獨立單位
不同手機的像素密度不同,同px的元素可能有不同的物理尺寸,這不利於多屏幕的適配。因此Android以160dpi(每英寸160像素)為基准定義了單位dp。
即1dp的元素在160dpi的屏幕用1個像素點px顯示,在320dpi的屏幕用2px顯示,但它們的顯示實際物理長度均為1/160=0.00625英寸。320dpi在同樣大小的屏幕內用了更多的像素顯示,所以顯得更「清晰」。
hdpi、xhdpi、xxhdpi
為了方便換算和顯示,Android預定義了一系列的dpi作為基准,例如mdpi定義為160dpi、hdpi定義為240dpi(實際上是一定的范圍,但不影響理解)。
我們拿到的圖片資源文件是以像素px為單位的,圖標的顯示卻是以dp為單位的。在使用ImageView進行顯示時,在規定好圖標的長寬后其內容會自動縮放(不同的ScaleType縮放的邏輯不一樣),像素過低的圖標會顯得「不清晰」。
適用於高dpi屏幕的圖標可以包含大量細節,在低dpi時直接縮放的話效果可能會出現鋸齒、模糊或無法識別其中的元素等情況。為了分別針對不同顯示密度的屏幕進行優化,Android在drawable和mipmap文件夾內為不同dpi的屏幕建立了不同的文件夾,在不同的設備上讀取相應dpi文件夾內的圖片資源進行顯示。
Toolbar的icon顯示邏輯
與ImageView這樣的控件相比,Toolbar顯示icon的邏輯就顯得比較簡單粗暴。在Material Design中,Toolbar的推薦高度為56dp,其中icon的尺寸建議為24dp,那么icon在不同dpi下的實際像素尺寸如下:
ldpi | 120dpi | 0.75 | 18px |
mdpi | 160dpi | 1 | 24px |
hdpi | 240dpi | 1.5 | 36px |
xhdpi | 320dpi | 2 | 48px |
xxhdpi | 480dpi | 3 | 72px |
xxxhdpi | 640dpi | 4 | 96px |
這里的問題在於,Toolbar的MenuView在顯示時讀取圖片資源后,不會檢查是否應該縮放,而是直接居中顯示。那么,如果你的圖片資源經過屏幕像素密度換算后不是「恰好」24dp的話,最后顯示的效果就會與期望的效果不一致。
例如,xhdpi文件夾存放的應該是48px的icon,如果放入了96px大小的icon的話在Toolbar上就會顯得2倍大。反之,在xxxhdpi中放入48px的icon看上去就會額外小。這也是為什么MD圖標庫中的icon會給mdpi到xxxhdpi一套圖標的原因。
解決方案
通常情況下Toolbar的icon都是純色的png圖片,體積非常小。以ic_search_white_24dp.png這個圖標為例,mdpi文件夾內的圖片大小為396字節,而xxxhdpi文件夾內的圖片大小也只有915字節,即使全部使用最大尺寸的圖標,對安裝包體積的影響也微乎其微。
而且Toolbar的icon都是抽象的圖標、細節不多,在低dip的設備上進行縮放時效果並沒有太大差別,根據Google發布的設備屏幕尺寸分布情況,hdpi以上的設備也已經占了85%以上。所以如果想要減小安裝包體積的話,Toolbar的icon是可以全部只使用一份96px*96px的圖片資源,並存放在xxxhdpi中的。
至於其他只在ImageView等控件中顯示的資源,如果只有一份的話,放在哪個文件夾內其實是無所謂的。
圖標設計規范
根據Material Design的設計規范,Toolbar icon的尺寸應為24dp,觸摸響應大小為48dp(Toolbar會自動進行設置),而在icon內部應有一定的留白,一般為2-4dp。因此對於一張96px的icon來說,圖片內的四周應有12px左右的邊距。
這里推薦一個神器 iconmonstr,在搜索框輸入關鍵詞找到想要的icon后,選擇png、調整大小為96px、邊距12px后,就可以直接下載了。