? ? ? ?回頭算算去扣,從正式開始做Android,剛好一年時間樊破,在這里所謂的互聯(lián)網(wǎng)寒冬毅然決然的入了Android的坑厅篓。不過話又說回來了秀存,我一直堅信技術(shù)的積累與大環(huán)境無關(guān),所以關(guān)鍵還是在于提升自己羽氮。之前在初入Android坑的工作中或链,都是使用印象筆記作為知識的積累,但是久而久之變得有點雜亂档押。因此最近年后一直考慮開始寫文章澳盐,把一些用到的知識點整理出來。最后選擇了簡書作為我的筆記本令宿。知識是需要沉淀的叼耙,總結(jié)出來的東西肯定會有不一樣的領(lǐng)悟。如果剛好這些東西能幫助到其他人粒没,那就更好了筛婉。
? ? ? ?好了,廢話這么多癞松,進入今天的正題吧爽撒。相信沒有做Android開發(fā)的朋友也一定知道一個事實:由于Android開源,因此采用Android系統(tǒng)的廠商非常之多响蓉,設(shè)備也非常多硕勿,而且各種尺寸和各種分辨率的組合也是多如牛毛。下面這張圖是從友盟發(fā)布的報告上截取的枫甲。因此適配就成Android開發(fā)中的必不可少的工作源武。下面我將從幾部分來說一說Android中的單位dp。
1想幻、基本概念
? ? ? ?首先要說的就是px粱栖。px是屏幕中可以顯示的最小元素單元。我們的手機(或平板)可以顯示的東西都是由一個個像素點組成的脏毯。在PC上查排,我們可以通過px這個單位就能把程序打扮的很漂亮,但是手機上卻不行抄沮。我舉個例子跋核,比如我們現(xiàn)在要在界面上畫一個button,設(shè)置按鈕寬度為200px叛买,我分別在1920*1080和800*480的兩臺設(shè)備上預(yù)覽的效果如下:
結(jié)果是一目了然砂代,在1920*1080的設(shè)備中,300px的像素大于只占屏幕寬度的不到三分之一率挣,而在800*480的設(shè)備中刻伊,卻占了一半還要多。因此,px作為單位肯定不行捶箱。google當(dāng)然也意識到了這個問題智什,因此引入了dp和sp兩個單位作為控件單位和字體單位。
我們先了解幾個相關(guān)的概念丁屎。
dp:也稱為dip荠锭,device independent pixels,設(shè)備獨立像素晨川。
dpi:全稱是 Dots Per Inch,每英寸所包含的像素數(shù)证九。
density:像素密度。計算公式為dpi/160共虑。
google官方規(guī)定愧怜,以dpi為160作為基準,即在一臺dpi為160的設(shè)備上妈拌,1px=1dp拥坛,此時該設(shè)備的density也為1。根據(jù)這個規(guī)定尘分,你可以對其他設(shè)備進行計算猜惋。例如一臺手機的屏幕寬是2英寸,長是3英寸音诫,分辨率為640*960惨奕。那么它的dpi值等于640/2(或者960/3)=320,density等于320/160=2雪位,1dp=1px*2竭钝。
這樣你應(yīng)該對dp這個單位有了一定的了解吧,我們最終看dp是實現(xiàn)了什么樣的效果雹洗。當(dāng)我把一個控件的寬度設(shè)置為1dp是香罐,在google定義的基準設(shè)備上,它所表示的真實長度=1/160英寸时肿。在上面定義的640*960的設(shè)備上庇茫。1dp=2px/320英寸。結(jié)果是一樣的螃成,都是1/160英寸旦签。也就是在不同的設(shè)備上所表現(xiàn)出的物理長度是一樣的。也就初步實現(xiàn)了適配寸宏。
但是實際情況可能沒有這么理想宁炫,例如我的手機魅藍note2,1920*1080,16:9氮凝,5.5英寸羔巢,通過代碼:getResources().getDisplayMetrics().densityDpi;得出的dpi值為480。通過手動計算,勾股定理得:寬為2.7英寸竿秆,高為4.8英寸启摄,dpi值等于:1080/2.7=400dpi,1920/4.8=400dpi幽钢。咦歉备?怎么兩個值不一樣,事實是這樣的:編譯ROM的時候會指定dpi,而且只能指定如下幾個值搅吁。
ldpi: 120dpi (mdpi x 0.75)
mdpi: 160dpi? (android 基準 dpi, 1dp=1px)
hdpi: 240dpi (mdpi x 1.5)
xhdpi: 320dpi(mdpi x 2)
xxhdpi: 480dpi(mdpi x 3)
xxxhdpi: 640dpi(mdpi x 4)
到目前這個階段威创,ldpi的設(shè)備已經(jīng)基本很少了,所以不做考慮谎懦。手機廠商應(yīng)該盡量讓手機的實際像素密度與ROM指定的值接近肚豺,請注意,是接近界拦,所以才會出現(xiàn)了上面的偏差吸申。假如屏幕 A 實際是 440dpi 的,ROM 被指定為 480 dpi享甸,那么屏幕顯示的實際上是 480/440=1.09 倍的真實大小截碴。
好了,上面費這么多話蛉威,其實只想說一絕話:
1dp約等于1/160英寸H盏ぁ!
2蚯嫌、Android屏幕適配方案
1哲虾、布局適配
做法:盡量使用相對布局
? ? ? ?目前為止,我們在進行布局界面的時候通常使用的布局包括: RelativeLayout择示、LinearLayout束凑、FrameLayout。推薦優(yōu)先使用RelativeLayout栅盲,RelativeLayout的特點是布局下的子控件之間使用相對位置的方式排列汪诉。即使屏幕的大小改變,視圖之前的相對位置都不會變化谈秫,與屏幕大小無關(guān)扒寄,靈活性很強。而LinearLayout布局無法控制子視圖之間的關(guān)系拟烫,只能一個挨一個的按照垂直或水平排列该编。而FrameLayout是把所有的元素都放在屏幕的左上方。如果要進行元素排布的話构灸,只能通過固定的dp值上渴。因此岸梨,對于屏幕適配而言,使用RelativeLayout是比較好的方案稠氮。
2曹阔、布局組件適配
? ? ? ?布局組件適配比較容易理解。即我們最常用的match_parent和wrap_content隔披。設(shè)置控件的寬和高時赃份,當(dāng)我們通過這兩個屬性值就可以設(shè)置控件的寬高為與父控件的寬高一致、適應(yīng)該控件的寬高奢米,而不需要指定固定的dp值抓韩。因此,也是屏幕適配優(yōu)先使用的控件屬性鬓长。
3谒拴、布局限定符適配
? 使用尺寸限定符
? ? ? ?Android 3.2之前通過small、normal涉波、large英上、xLarge分別標記小尺寸屏幕、正常尺寸屏幕啤覆、大尺寸屏幕苍日、超大尺寸屏幕。同一界面在不同的布局文件路徑下創(chuàng)建布局文件:res/layout/my_layout.xml窗声;
res/layout-large/my_layout.xml相恃;
res/layout-xlarge/my_layout.xml腋妙;
但是該種方法區(qū)分屏幕的邊界比較模糊碗啄,因此從Android 3.2之后就被棄用乾颁。鑒于目前4.0以下的系統(tǒng)基本可以忽略不計狗准,則此種方法目前來說基本是廢棄狀態(tài)。
??使用最小寬度限定符
? ? ? ?上面說到尺寸限定符已經(jīng)被廢棄掉了简烤,google的替代方案就是smallestWidth,設(shè)備的 smallestWidth 是屏幕可用高度和寬度的最小尺寸,smallestWidth 是設(shè)備的固定屏幕尺寸特性炮温;設(shè)備的 smallestWidth 不會隨屏幕方向的變化而改變。如果設(shè)備的屏幕上有一些永久性 UI 元素占據(jù)沿 smallestWidth 軸的空間牵舵,則系統(tǒng)會聲明 smallestWidth 小于實際屏幕尺寸柒啤。關(guān)鍵字:sw<N>dp。如:sw600dp畸颅、sw720dp担巩。同一界面在不同的布局文件路徑下創(chuàng)建布局文件:
res/layout/main_activity.xml
res/layout-sw600dp/main_activity.xml
??使用屏幕方向限定符
? ? ? ?如果我們要求給橫屏、豎屏顯示的布局不一樣没炒。就可以使用屏幕方向限定符來實現(xiàn)涛癌。在布局文件夾中增加關(guān)鍵字land、port實現(xiàn)。例如要在平板上實現(xiàn)橫豎屏顯示不用的布局拳话。同一界面在不同的布局文件路徑下創(chuàng)建布局文件:
res/values-sw600dp-land/layouts.xml:橫屏
res/values-sw600dp-port/layouts.xml:豎屏
3先匪、圖片資源適配
圖片資源適配優(yōu)先使用Android特用的九圖格式。
使用場景:當(dāng)我們需要使圖片在拉伸后還能保持一定的顯示效果弃衍,比如呀非,不能使圖片中的重要像素拉伸,不能使內(nèi)容區(qū)域受到拉伸的影響镜盯,我們就可以使用.9.png圖來實現(xiàn)岸裙。
使用方法說明:1、在九圖工具中速缆,選擇圖片的左邊和上邊降允,點選一個或多個像素點,即可把這些垂直水平方向選中的像素點進行拉伸處理艺糜。2拟糕、右邊和下邊是選擇內(nèi)容區(qū)域,在右邊和下邊畫上直線倦踢,交叉的區(qū)域就是內(nèi)容區(qū)域送滞,即文本顯示區(qū)域。
9圖可以根據(jù)屏幕的尺寸進行自由適配辱挥,因此是控件背景圖片的第一選擇犁嗅。但是并不是所有需要圖片的地方都要用9圖。其他需要圖片的地方晤碘,我們要根據(jù)前面說到的mdpi褂微、hdpi、xhdpi园爷、xxhdpi宠蚂、xxxhdpi幾種不同的設(shè)備進行切圖,你如果觀察過新建Android項目的app的icon的尺寸的話童社,你會發(fā)現(xiàn)在mipmap相關(guān)的幾個文件夾中求厕,它的尺寸分別為:48*48、72*72扰楼、96*96呀癣、144*144、192*192弦赖,它們轉(zhuǎn)換后都為48dp*48dp项栏,也就是說它們在設(shè)備上表現(xiàn)出的物理尺寸是基本一致的,也就實現(xiàn)了圖片的適配蹬竖。但是實際情況不可能這么完美沼沈,公司UI一般不會花這么大精力去做這么多圖對我們的設(shè)備進行適配流酬,另外也要考慮這樣apk的大小會增大不少。
所以一般是給出一種分辨率下的切圖列另,Android系統(tǒng)會自動根據(jù)圖片所放的文件夾和設(shè)備的密度進行相應(yīng)的縮放顯示康吵。這樣的方式圖片在app上也會有不錯的呈現(xiàn)效果。但是這個地方有不少細節(jié)需要注意访递,下一篇我們會在去講解晦嵌。
4、用戶界面流程適配
? ? ? ?前面有說到根據(jù)最小寬度限定符創(chuàng)建不同的布局文件拷姿。但是我們怎么在具體Activity中判斷究竟當(dāng)前設(shè)備是加載了哪個布局惭载,那些事件可以得到響應(yīng)。
1响巢、確定當(dāng)前布局
? 通過判斷某個控件是否為null描滔。這個控件如果只在一種布局下存在,那個可以使用此方法踪古。
? 通過判定某個控件的事件含长。如這個控件只在一種布局下才生效。
2伏穆、根據(jù)當(dāng)前的布局做出響應(yīng)
? ? ? ?有些操作可能會因當(dāng)前的具體布局而產(chǎn)生不同的結(jié)果拘泞。例如,在新聞閱讀器示例中枕扫,如果用戶界面處于雙面板模式下陪腌,那么點擊標題列表中的標題就會在右側(cè)面板中打開相應(yīng)報道;但如果用戶界面處于單面板模式下烟瞧,那么上述操作就會啟動一個獨立活動诗鸭。
3、重復(fù)使用其他活動中的片段
? ? ? ?多屏幕設(shè)計中的重復(fù)模式是指参滴,對于某些屏幕配置强岸,已實施界面的一部分會用作面板;但對于其他配置砾赔,這部分就會以獨立活動的形式存在蝌箍。例如,在新聞閱讀器示例中过蹂,對于較大的屏幕十绑,新聞報道文本會顯示在右側(cè)面板中聚至;但對于較小的屏幕酷勺,這些文本就會以獨立活動的形式存在。
在類似情況下扳躬,通炒嗨撸可以在多個活動中重復(fù)使用相同的 Fragment 子類以避免代碼重復(fù)甚亭。例如,在雙面板布局中使用了 ArticleFragment:
而在小屏幕上可以直接:
ArticleFragment frag =newArticleFragment();
getSupportFragmentManager().beginTransaction().add(android.R.id.content,?frag).commit();
這種方式與在 XML 布局中聲明片段的效果是一樣的击胜,但在這種情況下卻沒必要使用 XML 布局亏狰,因為此Fragment是此活動中的唯一組件。
另外偶摔,在Fragment中注意暇唾,不要針對具體Activity創(chuàng)建強耦合。要做到這一點辰斋,通巢咧荩可以定義一個接口,該接口概括了Fragment與其主Activity交互所需的全部方式宫仗,然后讓Activity更新界面够挂。這部分的內(nèi)容具體可參考凱子哥的一篇文章,鏈接在后面藕夫。
好了孽糖。關(guān)于Android中dp的認識我已經(jīng)把我所有的理解都放在這里了。如有錯誤請指正毅贮,共同進步办悟。
參考資料:
http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023
http://www.reibang.com/p/ec5a1a30694b