五行代碼搞定安卓全屏幕適配——簡單粗暴-低入侵白筹,無繼承智末,簡單高效

我的github文檔? ? ?***轉(zhuǎn)載源自 進(jìn)行了提示和完善

### 話不多說,先上解決方案

```java

/**? 將此文件直接復(fù)制到項(xiàng)目中遍蟋,不要忘記清單文件配置Application吹害,另 布局中使用pt

* (例如: android:layout_height="300pt" 用錯(cuò)可不適配哦!)

* feisher? @2017年8月11日14:52:27 二次整理虚青,原稿 為新浪大牛 布隆

* 458079442@qq.com

*/

public class MyApplication extends Application{

public final static float DESIGN_WIDTH = 750; //繪制頁面時(shí)參照的設(shè)計(jì)圖寬度

@Override

public void onCreate() {

super.onCreate();

resetDensity();//注意不要漏掉

}

@Override

public void onConfigurationChanged(Configuration newConfig) {

super.onConfigurationChanged(newConfig);

resetDensity();//這個(gè)方法重寫也是很有必要的

}

public void resetDensity(){

Point size = new Point();

((WindowManager)getSystemService(WINDOW_SERVICE)).getDefaultDisplay().getSize(size);

getResources().getDisplayMetrics().xdpi = size.x/DESIGN_WIDTH*72f;

}

}

```

## 為什么會有這么一篇文章呢它呀?

**現(xiàn)狀**

由于Android碎片化嚴(yán)重,屏幕適配一直是開發(fā)中較為頭疼的問題。面對市面上五花八門的屏幕大小與分辨率纵穿,Android基于dp與res目錄名稱來適配的方案已無法滿足一次編寫全屏幕適配的需求下隧,為了達(dá)到最優(yōu)的視覺效果,開發(fā)過程中總是需要花費(fèi)較多資源進(jìn)行適配谓媒。也有開發(fā)者給出了一些自己的解決方案淆院。首先來分析一下一些常見的解決方案的現(xiàn)狀:

1. ### **官方適配方案**

- dp。dp是Android開發(fā)中特有的一個(gè)單位句惯。與px不同土辩,dp是基于屏幕像素密度的一種單位。在密度低的屏幕上或許1dp=1px抢野,但在密度高的屏幕上可能1dp=4px拷淘。編寫布局xml時(shí),如果一個(gè)控件的長寬都使用dp來指定指孤,那么能確保該控件在各種大小與分辨率的屏幕下的絕對大小都大致相當(dāng)启涯。也就是說無論在pad下還是大小屏手機(jī)下,我們實(shí)際看到的該控件的大小是差不多的:

![](https://raw.githubusercontent.com/feisher/ScreenAdapter/master/dp.png)

- 資源目錄名恃轩。上圖可見雖然使用dp確保了控件在不同屏幕中的絕對大小一致结洼。這樣的好處在于,在大小相近的屏幕中叉跛,無論分辨率多大都不會對布局造成影響松忍;但是當(dāng)屏幕大小相差較大時(shí),僅保證控件的絕對大小看起來就有些問題了昧互。在res目錄下可以給各資源目錄都加上例如'-1920x1080'等后綴來適配不同的屏幕挽铁,具體規(guī)則可見官網(wǎng)文檔伟桅。這樣可以針對不同的屏幕提供不同的布局敞掘,甚至針對pad與手機(jī)提供兩套完全不同的布局樣式。但是通常情況下楣铁,設(shè)計(jì)師并不會對不同屏幕提供不同的設(shè)計(jì)圖玖雁,他們的需求僅僅是不同屏幕下控件對屏幕的相對大小一致,所以dp并不能滿足這一點(diǎn)盖腕,而對各種屏幕適配一遍又顯得略為繁瑣赫冬,并且修改也較為麻煩。通常我們需要的適配是這樣的:

![image](https://raw.githubusercontent.com/feisher/ScreenAdapter/master/hope.png)

- 百分比布局支持庫溃列。沒有使用過劲厌,但是deprecated in API level 26.0.0-beta1。

- ConstraintLayout听隐。百分比支持庫deprecated之后推薦使用的布局补鼻,看起來似乎略復(fù)雜。

### **玩家適配方案**

廣大玩家的適配目的很明確,目的就是要確狈绶叮控件在不同屏幕的相對大小一致咨跌,看起來一毛一樣的。以一位大神玩家的兩種適配方案為例:

- 方案一硼婿。編寫腳本將長度轉(zhuǎn)換成各分辨率下的長度锌半,缺點(diǎn)是難以覆蓋市面上的所有分辨率。

- 方案二寇漫。AutoLayout支持庫(安卓中**鴻洋**大神的開源)刊殉。該庫的想法非常好:對照設(shè)計(jì)圖,使用px編寫布局州胳,不影響預(yù)覽冗澈;繪制階段將對應(yīng)設(shè)計(jì)圖的px數(shù)值計(jì)算轉(zhuǎn)換為當(dāng)前屏幕下適配的大小陋葡;為簡化接入亚亲,inflate時(shí)自動將各Layout轉(zhuǎn)換為對應(yīng)的AutoLayout,從而不需要在所有的xml中更改腐缤。但是同時(shí)該庫也存在以下等問題:

- 擴(kuò)展性較差捌归。對于每一種ViewGroup都要對應(yīng)編寫對應(yīng)的AutoLayout進(jìn)行擴(kuò)展,對于各View的每個(gè)需要適配的屬性都要編寫代碼進(jìn)行適配擴(kuò)展岭粤;

- 在onMeasure階段進(jìn)行數(shù)值計(jì)算惜索。這對于非LayoutParams中的屬性存在較多不合理之處。比如在onMeasure時(shí)對TextView的textSize進(jìn)行換算并setTextSize剃浇,那么玩家在代碼中動態(tài)設(shè)置的textSize都會失效巾兆,因?yàn)樵诿看蝟nMesasure時(shí)都會重新被AutoLayout重新設(shè)置覆蓋。

- issue較多并且作者已**不再維護(hù)虎囚。**

2

### 進(jìn)行一下探索和嘗試如何角塑?

個(gè)人覺得AutoLayout的設(shè)計(jì)思想非常優(yōu)秀,但是將LayoutParams與屬性作為切入口在mesure過程中進(jìn)行轉(zhuǎn)換計(jì)算的方案存在效率與擴(kuò)展性等方面的問題淘讥。那么Android計(jì)算長度的收口在哪里圃伶,能不能在Android計(jì)算長度時(shí)進(jìn)行換算呢?如果能在Android計(jì)算長度時(shí)進(jìn)行換算蒲列,那么就不需要一系列多余的計(jì)算以及適配窒朋,一切問題就都迎刃而解了。

經(jīng)過一番尋覓蝗岖,發(fā)現(xiàn)系統(tǒng)進(jìn)行長度計(jì)算的收口為TypedValue中的applyDimension函數(shù)侥猩,傳入單位與value將其計(jì)算為對應(yīng)的px數(shù)值。

```java

public static float applyDimension(int unit, float value,DisplayMetrics metrics){

switch (unit) {

case COMPLEX_UNIT_PX:

return value;

case COMPLEX_UNIT_DIP:

return value * metrics.density;

case COMPLEX_UNIT_SP:

return value * metrics.scaledDensity;

case COMPLEX_UNIT_PT:

return value * metrics.xdpi * (1.0f/72);

case COMPLEX_UNIT_IN:

return value * metrics.xdpi;

case COMPLEX_UNIT_MM:

return value * metrics.xdpi * (1.0f/25.4f);

}

return 0;

}

```

- 可以看見換算方法非常簡單抵赢,而DisplayMetrics的所有屬性都是public的欺劳,不用反射就能修改洛退;

- pt的原意是長度單位磅,根據(jù)當(dāng)前屏幕與設(shè)計(jì)圖尺寸將metrics.xdpi進(jìn)行修改就可以實(shí)現(xiàn)將pt這個(gè)單位重定義成我們所需要的相對長度單位杰标,使修改之后計(jì)算出的1pt實(shí)際對應(yīng)的px/屏幕寬度px=1px/設(shè)計(jì)圖寬度px兵怯。

- 而這個(gè)DisplayMetrics從哪來?從源碼中可以看出一般為mContext.getResources().getDisplayMetrics()腔剂,這個(gè)mContext即為所在Activity媒区;

- Activity中所拿到的DisplayMetrics與Application中拿到的DisplayMetrics雖然不是一個(gè)實(shí)例,但是所有數(shù)值都相同掸犬,在Application中進(jìn)行更改也會影響到所有Activity中袜漩;

- Configuration的變化會導(dǎo)致DisplayMetrics的重新計(jì)算還原,需要handle湾碎;

- px,dp與sp都是平時(shí)常用的單位宙攻,而pt,in與mm幾乎沒有看見過,從這些不常見的單位下手正好可以不影響其他常用的單位介褥。

基于以上幾點(diǎn)座掘,便有了以下方案。

3

## 方案 (**注意劃重點(diǎn)了**)

適配的目標(biāo)是:完全按照設(shè)計(jì)圖上標(biāo)注的尺寸來編寫頁面柔滔,所編寫的頁面在所有大小與分辨率的屏幕上都表現(xiàn)一致溢陪,即控件在所有屏幕上相對于整個(gè)屏幕的相對大小都一致(看起來只是將設(shè)計(jì)圖縮放至屏幕大小)睛廊。

- 核心形真。使用冷門的pt作為長度單位。

- 繪制超全。編寫xml時(shí)完全對照設(shè)計(jì)稿上的尺寸來編寫咆霜,只不過單位換為pt。

- 需要在代碼中動態(tài)轉(zhuǎn)換成px時(shí)使用TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PT, value, metrics)嘶朱。

*UI給我們提供的設(shè)計(jì)圖是這樣的*

![img](https://raw.githubusercontent.com/feisher/ScreenAdapter/master/UI.jpg)

**創(chuàng)建什么樣的預(yù)覽使用的設(shè)備以設(shè)計(jì)圖為準(zhǔn)**

- 預(yù)覽蛾坯。實(shí)時(shí)預(yù)覽時(shí)繪制頁面是很重要的一個(gè)環(huán)節(jié)。以1334x750的設(shè)計(jì)圖為例见咒,為了實(shí)現(xiàn)于正常繪制時(shí)一樣的預(yù)覽功能偿衰,創(chuàng)建一個(gè)長為1334磅挂疆,寬為750磅的設(shè)備作為預(yù)覽改览,經(jīng)換算約為21.5英寸((sqrt(1334^2+750^2))/72)。**此處直接按照iphone 6尺寸設(shè)置4.7也沒影響**缤言。預(yù)覽時(shí)選擇這個(gè)設(shè)備即可宝当。

![img](https://raw.githubusercontent.com/feisher/ScreenAdapter/master/RomSetting.jpg)

-?怎么創(chuàng)建那個(gè)750設(shè)計(jì)稿分辨率的設(shè)備吶?看圖胆萧,_知道的同學(xué)請?zhí)^_

![img](https://raw.githubusercontent.com/feisher/ScreenAdapter/master/creatRom.png)

- 代碼處理庆揩。在Application的onCreate中與onConfigurationChanged中更改DisplayMetrics(其中DESIGN_WIDTH是繪制頁面時(shí)參照的設(shè)計(jì)圖寬度):

```java

/**? 將此文件直接復(fù)制到項(xiàng)目中俐东,不要忘記清單文件配置Application,另 布局中使用pt

* (例如: android:layout_height="300pt" 用錯(cuò)可不適配哦6┥巍)

* feisher? @2017年8月11日14:52:27 二次整理虏辫,

* 458079442@qq.com

*/

public class MyApplication extends Application{

public final static float DESIGN_WIDTH = 750; //繪制頁面時(shí)參照的設(shè)計(jì)圖寬度

@Override

public void onCreate() {

super.onCreate();

resetDensity();//注意不要漏掉

}

@Override

public void onConfigurationChanged(Configuration newConfig) {

super.onConfigurationChanged(newConfig);

resetDensity();//這個(gè)方法重寫也是很有必要的

}

public void resetDensity(){

Point size = new Point();

((WindowManager)getSystemService(WINDOW_SERVICE)).getDefaultDisplay().getSize(size);

getResources().getDisplayMetrics().xdpi = size.x/DESIGN_WIDTH*72f;

}

}

```

這樣繪制出來的頁面就跟設(shè)計(jì)圖幾乎完全一樣,無論大小屏上看起來就只是將設(shè)計(jì)圖縮放之后的結(jié)果锈拨。

適配前:

![img](https://raw.githubusercontent.com/feisher/ScreenAdapter/master/old.jpg)

適配后:

![img](https://raw.githubusercontent.com/feisher/ScreenAdapter/master/result.jpg)

*ps:引用自新浪微博? 布隆? 博客砌庄,感謝辛勤的開創(chuàng)者*

再次感謝辛勤的各位開發(fā)者

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市奕枢,隨后出現(xiàn)的幾起案子娄昆,更是在濱河造成了極大的恐慌,老刑警劉巖缝彬,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件萌焰,死亡現(xiàn)場離奇詭異,居然都是意外死亡谷浅,警方通過查閱死者的電腦和手機(jī)扒俯,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來一疯,“玉大人陵珍,你說我怎么就攤上這事∥ナ” “怎么了互纯?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長磕蒲。 經(jīng)常有香客問我留潦,道長,這世上最難降的妖魔是什么辣往? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任兔院,我火速辦了婚禮,結(jié)果婚禮上站削,老公的妹妹穿的比我還像新娘坊萝。我一直安慰自己,他們只是感情好许起,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布十偶。 她就那樣靜靜地躺著,像睡著了一般园细。 火紅的嫁衣襯著肌膚如雪惦积。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天猛频,我揣著相機(jī)與錄音狮崩,去河邊找鬼蛛勉。 笑死,一個(gè)胖子當(dāng)著我的面吹牛睦柴,可吹牛的內(nèi)容都是我干的诽凌。 我是一名探鬼主播,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼坦敌,長吁一口氣:“原來是場噩夢啊……” “哼皿淋!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起恬试,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤窝趣,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后训柴,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體哑舒,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年幻馁,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了洗鸵。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,096評論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡仗嗦,死狀恐怖膘滨,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情稀拐,我是刑警寧澤火邓,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站德撬,受9級特大地震影響铲咨,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蜓洪,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一纤勒、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧隆檀,春花似錦摇天、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至菊霜,卻和暖如春嗦锐,著一層夾襖步出監(jiān)牢的瞬間摹蘑,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工偎痛, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人构捡。 一個(gè)月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓液南,卻偏偏與公主長得像,于是被迫代替她去往敵國和親勾徽。 傳聞我的和親對象是個(gè)殘疾皇子滑凉,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評論 2 355

推薦閱讀更多精彩內(nèi)容