<a href="https://github.com/firedamp/rudeadaptdemo">我是demo快點我啊快點我</a>
由于android碎片化嚴重,螢幕适配一直是開發中較為頭疼的問題。面對市面上五花八門的螢幕大小與分辨率,android基于dp與res目錄名稱來适配的方案已無法滿足一次編寫全螢幕适配的需求,為了達到最優的視覺效果,開發過程中總是需要花費較多資源進行适配。也有開發者給出了一些自己的解決方案。首先來分析一下一些常見的解決方案的現狀:
官方适配方案
dp。dp是android開發中特有的一個機關。與px不同,dp是基于螢幕像素密度的一種機關。在密度低的螢幕上或許1dp=1px,但在密度高的螢幕上可能1dp=4px。編寫布局xml時,如果一個控件的長寬都使用dp來指定,那麼能確定該控件在各種大小與分辨率的螢幕下的絕對大小都大緻相當。也就是說無論在pad下還是大小屏手機下,我們實際看到的該控件的大小是差不多的:
玩家适配方案。廣大玩家的适配目的很明确,目的就是要確定控件在不同螢幕的相對大小一緻,看起來一毛一樣的。以一位大神玩家的兩種适配方案為例:
擴充性較差。對于每一種viewgroup都要對應編寫對應的autolayout進行擴充,對于各view的每個需要适配的屬性都要編寫代碼進行适配擴充;
在onmeasure階段進行數值計算。消耗性能,并且這對于非layoutparams中的屬性存在較多不合理之處。比如在onmeasure時對textview的textsize進行換算并settextsize,那麼玩家在代碼中動态設定的textsize都會失效,因為在每次onmesasure時都會重新被autolayout重新設定覆寫。
issue較多并且作者已不再維護。
個人覺得autolayout的設計思想非常優秀,但是将layoutparams與屬性作為切入口在mesure過程中進行轉換計算的方案存在效率與擴充性等方面的問題。那麼android計算長度的收口在哪裡,能不能在android計算長度時進行換算呢?如果能在android計算長度時進行換算,那麼就不需要一系列多餘的計算以及适配,一切問題就都迎刃而解了。
經過一番尋覓,發現系統進行長度計算的收口為<code>typedvalue</code>中的<code>applydimension</code>函數,傳入機關與value将其計算為對應的px數值。
可以看見換算方法非常簡單,而displaymetrics的所有屬性都是<code>public</code>的,不用反射就能修改;
pt的原意是長度機關磅,根據目前螢幕與設計圖尺寸将<code>metrics.xdpi</code>進行修改就可以實作将pt這個機關重定義成我們所需要的相對長度機關,使<code>修改之後計算出的1pt實際對應的px/螢幕寬度px=1px/設計圖寬度px</code>。
而這個displaymetrics從哪來?從源碼中可以看出一般為<code>mcontext.getresources().getdisplaymetrics()</code>,這個<code>mcontext</code>即為所在activity;
activity中所拿到的displaymetrics與application中拿到的dislaymetrics雖然不是一個執行個體,但是所有數值都相同,在application中進行更改也會影響到所有activity中;
橫豎屏切換等configuration的變化會導緻displaymetrics的重新計算還原,需要重新處理;
px,dp與sp都是平時常用的機關,而pt,in與mm幾乎沒有看見過,從這些不常見的機關下手正好可以不影響其他常用的機關。
基于以上幾點,遍有了以下方案。
适配的目标是:完全按照設計圖上标注的尺寸來編寫頁面,所編寫的頁面在所有大小與分辨率的螢幕上都表現一緻,即控件在所有螢幕上相對于整個螢幕的相對大小都一緻(看起來隻是将設計圖縮放至螢幕大小)。
核心。使用冷門的pt作為長度機關,按照上述想法将其重定義為與螢幕大小相關的相對機關,不會對dp等常用機關的使用造成影響。
繪制。編寫xml時完全對照設計稿上的尺寸來編寫,隻不過機關換為pt。
如果需要在代碼中動态轉換成px的話,使用<code>typedvalue.applydimension(typedvalue.complex_unit_pt, value, metrics)</code>。
預覽。實時預覽時繪制頁面是很重要的一個環節。以1334x750的設計圖為例,為了實作于正常繪制時一樣的預覽功能,建立一個長為1334磅,寬為750磅的裝置作為預覽,經換算約為21.5英寸(<code>(sqrt(1334^2+750^2))/72</code>)。預覽時選擇這個裝置即可。
這樣繪制出來的頁面就跟設計圖幾乎完全一樣,無論大小屏上看起來就隻是将設計圖縮放之後的結果。
适配前(左圖api19 400x800, 右圖api24 1440x2560):
适配後(左圖api19 400x800, 右圖api24 1440x2560):