Carson帶你學(xué)Android:屏幕適配-最全面的解決方案

前言

Android的屏幕適配一直以來都在折磨著我們Android開發(fā)者,本文將結(jié)合:

給你帶來一種全新杜窄、全面而邏輯清晰的Android屏幕適配思路肠骆,只要你認(rèn)真閱讀,保證你能解決Android的屏幕適配問題塞耕!


目錄

Android屏幕適配解決方案.png

定義

使得某一元素在Android不同尺寸蚀腿、不同分辨率的手機(jī)上具備相同的顯示效果


相關(guān)重要概念

屏幕尺寸

  • 含義:手機(jī)對(duì)角線的物理尺寸
  • 單位:英寸(inch),1英寸=2.54cm

Android手機(jī)常見的尺寸有5寸扫外、5.5寸莉钙、6寸等等

屏幕分辨率

  • 含義:手機(jī)在橫向、縱向上的像素點(diǎn)數(shù)總和
  1. 一般描述成屏幕的"寬x高”=AxB
  2. 含義:屏幕在橫向方向(寬度)上有A個(gè)像素點(diǎn)筛谚,在縱向方向
    (高)有B個(gè)像素點(diǎn)
  3. 例子:1080x1920磁玉,即寬度方向上有1080個(gè)像素點(diǎn),在高度方向上有1920個(gè)像素點(diǎn)
  • 單位:px(pixel)刻获,1px=1像素點(diǎn)

UI設(shè)計(jì)師的設(shè)計(jì)圖會(huì)以px作為統(tǒng)一的計(jì)量單位

  • Android手機(jī)常見的分辨率:320x480蜀涨、480x800瞎嬉、720x1280、1080x1920

屏幕像素密度

  • 含義:每英寸的像素點(diǎn)數(shù)
  • 單位:dpi(dots per ich)

假設(shè)設(shè)備內(nèi)每英寸有160個(gè)像素厚柳,那么該設(shè)備的屏幕像素密度=160dpi

  • 安卓手機(jī)對(duì)于每類手機(jī)屏幕大小都有一個(gè)相應(yīng)的屏幕像素密度:
密度類型 代表的分辨率(px) 屏幕像素密度(dpi)
低密度(ldpi) 240x320 120
中密度(mdpi) 320x480 160
高密度(hdpi) 480x800 240
超高密度(xhdpi) 720x1280 320
超超高密度(xxhdpi) 1080x1920 480

屏幕尺寸氧枣、分辨率、像素密度三者關(guān)系

一部手機(jī)的分辨率是寬x高别垮,屏幕大小是以寸為單位便监,那么三者的關(guān)系是:

三者關(guān)系示意圖

數(shù)學(xué)不太差的人應(yīng)該能懂.....吧?

不懂沒關(guān)系碳想,在這里舉個(gè)例子
假設(shè)一部手機(jī)的分辨率是1080x1920(px)烧董,屏幕大小是5寸,問密度是多少胧奔?
解:請(qǐng)直接套公式

解答過程

密度無關(guān)像素

  • 含義:density-independent pixel逊移,叫dp或dip,與終端上的實(shí)際物理像素點(diǎn)無關(guān)龙填。
  • 單位:dp胳泉,可以保證在不同屏幕像素密度的設(shè)備上顯示相同的效果
  1. Android開發(fā)時(shí)用dp而不是px單位設(shè)置圖片大小袜匿,是Android特有的單位
  2. 場(chǎng)景:假如同樣都是畫一條長(zhǎng)度是屏幕一半的線帖旨,如果使用px作為計(jì)量單位,那么在480x800分辨率手機(jī)上設(shè)置應(yīng)為240px冤竹;在320x480的手機(jī)上應(yīng)設(shè)置為160px宿礁,二者設(shè)置就不同了案铺;如果使用dp為單位,在這兩種分辨率下梆靖,160dp都顯示為屏幕一半的長(zhǎng)度控汉。
  • dp與px的轉(zhuǎn)換
    因?yàn)閡i設(shè)計(jì)師給你的設(shè)計(jì)圖是以px為單位的,Android開發(fā)則是使用dp作為單位的涤姊,那么我們需要進(jìn)行轉(zhuǎn)換:
密度類型 代表的分辨率(px) 屏幕密度(dpi) 換算(px/dp) 比例
低密度(ldpi) 240x320 120 1dp=0.75px 3
中密度(mdpi) 320x480 160 1dp=1px 4
高密度(hdpi) 480x800 240 1dp=1.5px 6
超高密度(xhdpi) 720x1280 320 1dp=2px 8
超超高密度(xxhdpi) 1080x1920 480 1dp=3px 12

在Android中暇番,規(guī)定以160dpi(即屏幕分辨率為320x480)為基準(zhǔn):1dp=1px

獨(dú)立比例像素

  • 含義:scale-independent pixel嗤放,叫sp或sip
  • 單位:sp
  1. Android開發(fā)時(shí)用此單位設(shè)置文字大小思喊,可根據(jù)字體大小首選項(xiàng)進(jìn)行縮放
  2. 推薦使用12sp、14sp次酌、18sp恨课、22sp作為字體設(shè)置的大小,不推薦使用奇數(shù)和小數(shù)岳服,容易造成精度的丟失問題剂公;小于12sp的字體會(huì)太小導(dǎo)致用戶看不清

請(qǐng)把上面的概念記住,因?yàn)橄旅嬷v解都會(huì)用到吊宋!


為什么要進(jìn)行Android屏幕適配

由于Android系統(tǒng)的開放性纲辽,任何用戶、開發(fā)者、OEM廠商拖吼、運(yùn)營(yíng)商都可以對(duì)Android進(jìn)行定制鳞上,于是導(dǎo)致:

  • Android系統(tǒng)碎片化:小米定制的MIUI、魅族定制的flyme吊档、華為定制的EMUI等等

當(dāng)然都是基于Google原生系統(tǒng)定制的

  • Android機(jī)型屏幕尺寸碎片化:5寸篙议、5.5寸、6寸等等
  • Android屏幕分辨率碎片化:320x480怠硼、480x800鬼贱、720x1280、1080x1920

據(jù)友盟指數(shù)顯示香璃,統(tǒng)計(jì)至2015年12月这难,支持Android的設(shè)備共有27796種

當(dāng)Android系統(tǒng)、屏幕尺寸葡秒、屏幕密度出現(xiàn)碎片化的時(shí)候雁佳,就很容易出現(xiàn)同一元素在不同手機(jī)上顯示不同的問題。

試想一下這么一個(gè)場(chǎng)景:
為4.3寸屏幕準(zhǔn)備的UI設(shè)計(jì)圖同云,運(yùn)行在5.0寸的屏幕上糖权,很可能在右側(cè)和下側(cè)存在大量的空白;而5.0寸的UI設(shè)計(jì)圖運(yùn)行到4.3寸的設(shè)備上炸站,很可能顯示不下星澳。

為了保證用戶獲得一致的用戶體驗(yàn)效果:

使得某一元素在Android不同尺寸、不同分辨率的手機(jī)上具備相同的顯示效果

于是旱易,我們便需要對(duì)Android屏幕進(jìn)行適配禁偎。


屏幕適配問題的本質(zhì)

  • 使得“布局”、“布局組件”阀坏、“圖片資源”如暖、“用戶界面流程”匹配不同的屏幕尺寸

使得布局、布局組件自適應(yīng)屏幕尺寸忌堂;
根據(jù)屏幕的配置來加載相應(yīng)的UI布局盒至、用戶界面流程

  • 使得“圖片資源”匹配不同的屏幕密度

解決方案

  • 問題:如何進(jìn)行屏幕尺寸匹配?
  • 答:
屏幕尺寸適配解決方案.png

“布局”匹配

本質(zhì)1:使得布局元素自適應(yīng)屏幕尺寸

  • 做法
    使用相對(duì)布局(RelativeLayout)士修,禁用絕對(duì)布局(AbsoluteLayout)

開發(fā)中枷遂,我們使用的布局一般有:

  • 線性布局(Linearlayout)
  • 相對(duì)布局(RelativeLayout)
  • 幀布局(FrameLayout)
  • 絕對(duì)布局(AbsoluteLayout)

由于絕對(duì)布局(AbsoluteLayout)適配性極差,所以極少使用棋嘲。

對(duì)于線性布局(Linearlayout)酒唉、相對(duì)布局(RelativeLayout)和幀布局(FrameLayout)需要根據(jù)需求進(jìn)行選擇,但要記追幸啤:

  • RelativeLayout
    布局的子控件之間使用相對(duì)位置的方式排列痪伦,因?yàn)镽elativeLayout講究的是相對(duì)位置侄榴,即使屏幕的大小改變,視圖之前的相對(duì)位置都不會(huì)變化网沾,與屏幕大小無關(guān)牲蜀,靈活性很強(qiáng)
  • LinearLayout
    通過多層嵌套LinearLayout和組合使
    用"wrap_content"和"match_parent"已經(jīng)可以構(gòu)建出足夠復(fù)雜的布局。但是LinearLayout無法準(zhǔn)確地控制子視圖之間的位置關(guān)系绅这,只能簡(jiǎn)單的一個(gè)挨著一個(gè)地排列

所以涣达,對(duì)于屏幕適配來說,使用相對(duì)布局(RelativeLayout)將會(huì)是更好的解決方案

本質(zhì)2:根據(jù)屏幕的配置來加載相應(yīng)的UI布局

應(yīng)用場(chǎng)景:需要為不同屏幕尺寸的設(shè)備設(shè)計(jì)不同的布局

  • 做法:使用限定符
  • 作用:通過配置限定符使得程序在運(yùn)行時(shí)根據(jù)當(dāng)前設(shè)備的配置(屏幕尺寸)自動(dòng)加載合適的布局資源
  • 限定符類型:
  • 尺寸(size)限定符
  • 最小寬度(Smallest-width)限定符
  • 布局別名
  • 屏幕方向(Orientation)限定符

尺寸(size)限定符

  • 使用場(chǎng)景:當(dāng)一款應(yīng)用顯示的內(nèi)容較多证薇,希望進(jìn)行以下設(shè)置:
  • 在平板電腦和電視的屏幕(>7英寸)上:實(shí)施“雙面板”模式以同時(shí)顯示更多內(nèi)容
  • 在手機(jī)較小的屏幕上:使用單面板分別顯示內(nèi)容

因此度苔,我們可以使用尺寸限定符(layout-large)通過創(chuàng)建一個(gè)文件

res/layout-large/main.xml

來完成上述設(shè)定:

  • 讓系統(tǒng)在屏幕尺寸>7英寸時(shí)采用適配平板的雙面板布局
  • 反之(默認(rèn)情況下)采用適配手機(jī)的單面板布局

文件配置如下:

  • 適配手機(jī)的單面板(默認(rèn))布局:res/layout/main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <fragment android:id="@+id/headlines"
              android:layout_height="fill_parent"
              android:name="com.example.android.newsreader.HeadlinesFragment"
              android:layout_width="match_parent" />
</LinearLayout>
  • 適配尺寸>7寸平板的雙面板布局::res/layout-large/main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="horizontal">
    <fragment android:id="@+id/headlines"
              android:layout_height="fill_parent"
              android:name="com.example.android.newsreader.HeadlinesFragment"
              android:layout_width="400dp"
              android:layout_marginRight="10dp"/>
    <fragment android:id="@+id/article"
              android:layout_height="fill_parent"
              android:name="com.example.android.newsreader.ArticleFragment"
              android:layout_width="fill_parent" />
</LinearLayout>

請(qǐng)注意:

  • 兩個(gè)布局名稱均為main.xml,只有布局的目錄名不同:第一個(gè)布局的目錄名為:layout浑度,第二個(gè)布局的目錄名為:layout-large寇窑,包含了尺寸限定符(large)
  • 被定義為大屏的設(shè)備(7寸以上的平板)會(huì)自動(dòng)加載包含了large限定符目錄的布局,而小屏設(shè)備會(huì)加載另一個(gè)默認(rèn)的布局

但要注意的是箩张,這種方式只適合Android 3.2版本之前甩骏。

最小寬度(Smallest-width)限定符

  • 背景:上述提到的限定符“l(fā)arge”具體是指多大呢?似乎沒有一個(gè)定量的指標(biāo)先慷,這便意味著可能沒辦法準(zhǔn)確地根據(jù)當(dāng)前設(shè)備的配置(屏幕尺寸)自動(dòng)加載合適的布局資源
  • 例子:比如說large同時(shí)包含著5寸和7寸饮笛,這意味著使用“l(fā)arge”限定符的話我沒辦法實(shí)現(xiàn)為5寸和7寸的平板電腦分別加載不同的布局

于是,在Android 3.2及之后版本论熙,引入了最小寬度(Smallest-width)限定符

定義:通過指定某個(gè)最小寬度(以 dp 為單位)來精確定位屏幕從而加載不同的UI資源

  • 使用場(chǎng)景

你需要為標(biāo)準(zhǔn) 7 英寸平板電腦匹配雙面板布局(其最小寬度為 600 dp)福青,在手機(jī)(較小的屏幕上)匹配單面板布局

解決方案:您可以使用上文中所述的單面板和雙面板這兩種布局,但您應(yīng)使用 sw600dp 指明雙面板布局僅適用于最小寬度為 600 dp 的屏幕脓诡,而不是使用 large 尺寸限定符无午。

  • sw xxxdp,即small width的縮寫祝谚,其不區(qū)分方向宪迟,即無論是寬度還是高度,只要大于 xxxdp交惯,就采用次此布局
  • 例子:使用了layout-sw 600dp的最小寬度限定符次泽,即無論是寬度還是高度,只要大于600dp商玫,就采用layout-sw 600dp目錄下的布局

代碼展示:

  • 適配手機(jī)的單面板(默認(rèn))布局:res/layout/main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <fragment android:id="@+id/headlines"
              android:layout_height="fill_parent"
              android:name="com.example.android.newsreader.HeadlinesFragment"
              android:layout_width="match_parent" />
</LinearLayout>
  • 適配尺寸>7寸平板的雙面板布局:res/layout-sw600dp/main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="horizontal">
    <fragment android:id="@+id/headlines"
              android:layout_height="fill_parent"
              android:name="com.example.android.newsreader.HeadlinesFragment"
              android:layout_width="400dp"
              android:layout_marginRight="10dp"/>
    <fragment android:id="@+id/article"
              android:layout_height="fill_parent"
              android:name="com.example.android.newsreader.ArticleFragment"
              android:layout_width="fill_parent" />
</LinearLayout>
  • 對(duì)于最小寬度≥ 600 dp 的設(shè)備
    系統(tǒng)會(huì)自動(dòng)加載 layout-sw600dp/main.xml(雙面板)布局箕憾,否則系統(tǒng)就會(huì)選擇 layout/main.xml(單面板)布局
    (這個(gè)選擇過程是Android系統(tǒng)自動(dòng)選擇的)

使用布局別名

設(shè)想這么一個(gè)場(chǎng)景

當(dāng)你需要同時(shí)為Android 3.2版本前和Android 3.2版本后的手機(jī)進(jìn)行屏幕尺寸適配的時(shí)候,由于尺寸限定符僅用于Android 3.2版本前拳昌,最小寬度限定符僅用于Android 3.2版本后,所以這會(huì)帶來一個(gè)問題钠龙,為了很好地進(jìn)行屏幕尺寸的適配炬藤,你需要同時(shí)維護(hù)layout-sw600dp和layout-large的兩套main.xml平板布局御铃,如下:

  • 適配手機(jī)的單面板(默認(rèn))布局:res/layout/main.xml
  • 適配尺寸>7寸平板的雙面板布局(Android 3.2前):res/layout-large/main.xml
  • 適配尺寸>7寸平板的雙面板布局(Android 3.2后)res/layout-sw600dp/main.xml

最后的兩個(gè)文件的xml內(nèi)容是完全相同的,這會(huì)帶來:文件名的重復(fù)從而帶來一些列后期維護(hù)的問題

于是為了要解決這種重復(fù)問題沈矿,我們引入了“布局別名”

還是上面的例子上真,你可以定義以下布局:

  • 適配手機(jī)的單面板(默認(rèn))布局:res/layout/main.xml
  • 適配尺寸>7寸平板的雙面板布局:res/layout/main_twopanes.xml

然后加入以下兩個(gè)文件,以便進(jìn)行Android 3.2前和Android 3.2后的版本雙面板布局適配:

  1. res/values-large/layout.xml(Android 3.2之前的雙面板布局)
<resources>
    <item name="main" type="layout">@layout/main_twopanes</item>
</resources>
  1. res/values-sw600dp/layout.xml(Android 3.2及之后的雙面板布局)
<resources>
<item name="main" type="layout">@layout/main_twopanes</item>
</resources>

注:

  • 最后兩個(gè)文件有著相同的內(nèi)容羹膳,但是它們并沒有真正去定義布局睡互,它們僅僅只是將main設(shè)置成了@layout/main_twopanes的別名
  • 由于這些文件包含 large 和 sw600dp 選擇器,因此陵像,系統(tǒng)會(huì)將此文件匹配到不同版本的>7寸平板上:
    a. 版本低于 3.2 的平板會(huì)匹配 large的文件
    b. 版本高于 3.2 的平板會(huì)匹配 sw600dp的文件

這樣兩個(gè)layout.xml都只是引用了@layout/main_twopanes就珠,就避免了重復(fù)定義布局文件的情況

屏幕方向(Orientation)限定符

  • 使用場(chǎng)景:根據(jù)屏幕方向進(jìn)行布局的調(diào)整

取以下為例子:

  • 小屏幕, 豎屏: 單面板
  • 小屏幕, 橫屏: 單面板
  • 7 英寸平板電腦,縱向:?jiǎn)蚊姘逍延保瑤Р僮鳈?/li>
  • 7 英寸平板電腦妻怎,橫向:雙面板,寬泞歉,帶操作欄
  • 10 英寸平板電腦逼侦,縱向:雙面板,窄腰耙,帶操作欄
  • 10 英寸平板電腦榛丢,橫向:雙面板,寬挺庞,帶操作欄
  • 電視涕滋,橫向:雙面板,寬挠阁,帶操作欄

方法是:

  • 先定義類別:?jiǎn)?雙面板宾肺、是否帶操作欄、寬/窄

定義在 res/layout/ 目錄下的某個(gè) XML 文件中

  • 再進(jìn)行相應(yīng)的匹配:屏幕尺寸(小屏侵俗、7寸锨用、10寸)、方向(橫隘谣、縱)

使用布局別名進(jìn)行匹配

  1. 在 res/layout/ 目錄下的某個(gè) XML 文件中定義所需要的布局類別
    (單/雙面板增拥、是否帶操作欄、寬/窄)
    res/layout/onepane.xml:(單面板)
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    android:orientation="vertical"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent">  
  
    <fragment android:id="@+id/headlines"  
              android:layout_height="fill_parent"  
              android:name="com.example.android.newsreader.HeadlinesFragment"  
              android:layout_width="match_parent" />  
</LinearLayout>  

res/layout/onepane_with_bar.xml:(單面板帶操作欄)

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    android:orientation="vertical"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent">  
    <LinearLayout android:layout_width="match_parent"   
                  android:id="@+id/linearLayout1"    
                  android:gravity="center"  
                  android:layout_height="50dp">  
        <ImageView android:id="@+id/imageView1"   
                   android:layout_height="wrap_content"  
                   android:layout_width="wrap_content"  
                   android:src="@drawable/logo"  
                   android:paddingRight="30dp"  
                   android:layout_gravity="left"  
                   android:layout_weight="0" />  
        <View android:layout_height="wrap_content"   
              android:id="@+id/view1"  
              android:layout_width="wrap_content"  
              android:layout_weight="1" />  
        <Button android:id="@+id/categorybutton"  
                android:background="@drawable/button_bg"  
                android:layout_height="match_parent"  
                android:layout_weight="0"  
                android:layout_width="120dp"  
                style="@style/CategoryButtonStyle"/>  
    </LinearLayout>  
  
    <fragment android:id="@+id/headlines"   
              android:layout_height="fill_parent"  
              android:name="com.example.android.newsreader.HeadlinesFragment"  
              android:layout_width="match_parent" />  
</LinearLayout> 

res/layout/twopanes.xml:(雙面板寻歧,寬布局)

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="horizontal">
    <fragment android:id="@+id/headlines"
              android:layout_height="fill_parent"
              android:name="com.example.android.newsreader.HeadlinesFragment"
              android:layout_width="400dp"
              android:layout_marginRight="10dp"/>
    <fragment android:id="@+id/article"
              android:layout_height="fill_parent"
              android:name="com.example.android.newsreader.ArticleFragment"
              android:layout_width="fill_parent" />
</LinearLayout>

res/layout/twopanes_narrow.xml:(雙面板掌栅,窄布局)

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="horizontal">
    <fragment android:id="@+id/headlines"
              android:layout_height="fill_parent"
              android:name="com.example.android.newsreader.HeadlinesFragment"
              android:layout_width="200dp"
              android:layout_marginRight="10dp"/>
    <fragment android:id="@+id/article"
              android:layout_height="fill_parent"
              android:name="com.example.android.newsreader.ArticleFragment"
              android:layout_width="fill_parent" />
</LinearLayout>

2.使用布局別名進(jìn)行相應(yīng)的匹配
(屏幕尺寸(小屏、7寸码泛、10寸)猾封、方向(橫、縱))
res/values/layouts.xml:(默認(rèn)布局)

<resources>  
    <item name="main_layout" type="layout">@layout/onepane_with_bar</item>  
    <bool name="has_two_panes">false</bool>  
</resources> 

可為resources設(shè)置bool噪珊,通過獲取其值來動(dòng)態(tài)判斷目前已處在哪個(gè)適配布局

res/values-sw600dp-land/layouts.xml
(大屏晌缘、橫向齐莲、雙面板、寬-Andorid 3.2版本后)

<resources>
    <item name="main_layout" type="layout">@layout/twopanes</item>
    <bool name="has_two_panes">true</bool>
</resources>

res/values-sw600dp-port/layouts.xml
(大屏磷箕、縱向选酗、單面板帶操作欄-Andorid 3.2版本后)

<resources>
    <item name="main_layout" type="layout">@layout/onepane</item>
    <bool name="has_two_panes">false</bool>
</resources>

res/values-large-land/layouts.xml
(大屏、橫向岳枷、雙面板芒填、寬-Andorid 3.2版本前)

<resources>
    <item name="main_layout" type="layout">@layout/twopanes</item>
    <bool name="has_two_panes">true</bool>
</resources>

res/values-large-port/layouts.xml
(大屏、縱向空繁、單面板帶操作欄-Andorid 3.2版本前)

<resources>
    <item name="main_layout" type="layout">@layout/onepane</item>
    <bool name="has_two_panes">false</bool>
</resources>

這里沒有完全把全部尺寸匹配類型的代碼貼出來殿衰,大家可以自己去嘗試把其補(bǔ)充完整


“布局組件”匹配

本質(zhì):使得布局組件自適應(yīng)屏幕尺寸

  • 做法
    使用"wrap_content"、"match_parent"和"weight“來控制視圖組件的寬度和高度
  • "wrap_content"
    相應(yīng)視圖的寬和高就會(huì)被設(shè)定成所需的最小尺寸以適應(yīng)視圖中的內(nèi)容
  • "match_parent"(在Android API 8之前叫作"fill_parent")
    視圖的寬和高延伸至充滿整個(gè)父布局
  • "weight"
    1.定義:是線性布局(Linelayout)的一個(gè)獨(dú)特比例分配屬性
    2.作用:使用此屬性設(shè)置權(quán)重家厌,然后按照比例對(duì)界面進(jìn)行空間的分配播玖,公式計(jì)算是:控件寬度=控件設(shè)置寬度+剩余空間所占百分比寬幅
    具體可以參考這篇文章,講解得非常詳細(xì)

通過使用"wrap_content"饭于、"match_parent"和"weight"來替代硬編碼的方式定義視圖大小&位置蜀踏,你的視圖要么僅僅使用了需要的那邊一點(diǎn)空間,要么就會(huì)充滿所有可用的空間掰吕,即按需占據(jù)空間大小果覆,能讓你的布局元素充分適應(yīng)你的屏幕尺寸


“圖片資源”匹配

本質(zhì):使得圖片資源在不同屏幕密度上顯示相同的像素效果

  • 做法:使用自動(dòng)拉伸位圖:Nine-Patch的圖片類型
    假設(shè)需要匹配不同屏幕大小,你的圖片資源也必須自動(dòng)適應(yīng)各種屏幕尺寸

使用場(chǎng)景:一個(gè)按鈕的背景圖片必須能夠隨著按鈕大小的改變而改變殖熟。
使用普通的圖片將無法實(shí)現(xiàn)上述功能,因?yàn)檫\(yùn)行時(shí)會(huì)均勻地拉伸或壓縮你的圖片

  • 解決方案:使用自動(dòng)拉伸位圖(nine-patch圖片)局待,后綴名是.9.png,它是一種被特殊處理過的PNG圖片菱属,設(shè)計(jì)時(shí)可以指定圖片的拉伸區(qū)域和非拉伸區(qū)域钳榨;使用時(shí),系統(tǒng)就會(huì)根據(jù)控件的大小自動(dòng)地拉伸你想要拉伸的部分

1.必須要使用.9.png后綴名纽门,因?yàn)橄到y(tǒng)就是根據(jù)這個(gè)來區(qū)別nine-patch圖片和普通的PNG圖片的薛耻;
2.當(dāng)你需要在一個(gè)控件中使用nine-patch圖片時(shí),如

android:background="@drawable/button"

系統(tǒng)就會(huì)根據(jù)控件的大小自動(dòng)地拉伸你想要拉伸的部分


”用戶界面流程“匹配

  • 使用場(chǎng)景:我們會(huì)根據(jù)設(shè)備特點(diǎn)顯示恰當(dāng)?shù)牟季郑沁@樣做赏陵,會(huì)使得用戶界面流程可能會(huì)有所不同饼齿。
  • 例如,如果應(yīng)用處于雙面板模式下蝙搔,點(diǎn)擊左側(cè)面板上的項(xiàng)即可直接在右側(cè)面板上顯示相關(guān)內(nèi)容缕溉;而如果該應(yīng)用處于單面板模式下,點(diǎn)擊相關(guān)的內(nèi)容應(yīng)該跳轉(zhuǎn)到另外一個(gè)Activity進(jìn)行后續(xù)的處理吃型。

本質(zhì):根據(jù)屏幕的配置來加載相應(yīng)的用戶界面流程

  • 做法
    進(jìn)行用戶界面流程的自適應(yīng)配置:
  1. 確定當(dāng)前布局
  2. 根據(jù)當(dāng)前布局做出響應(yīng)
  3. 重復(fù)使用其他活動(dòng)中的片段
  4. 處理屏幕配置變化
  • 步驟1:確定當(dāng)前布局
    由于每種布局的實(shí)施都會(huì)稍有不同证鸥,因此我們需要先確定當(dāng)前向用戶顯示的布局。例如,我們可以先了解用戶所處的是“單面板”模式還是“雙面板”模式敌土。要做到這一點(diǎn)镜硕,可以通過查詢指定視圖是否存在以及是否已顯示出來运翼。
public class NewsReaderActivity extends FragmentActivity {
    boolean mIsDualPane;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main_layout);

        View articleView = findViewById(R.id.article);
        mIsDualPane = articleView != null &&
                        articleView.getVisibility() == View.VISIBLE;
    }
}

這段代碼用于查詢“報(bào)道”面板是否可用返干,與針對(duì)具體布局的硬編碼查詢相比,這段代碼的靈活性要大得多血淌。

  • 步驟2:根據(jù)當(dāng)前布局做出響應(yīng)
    有些操作可能會(huì)因當(dāng)前的具體布局而產(chǎn)生不同的結(jié)果矩欠。

例如,在新聞閱讀器示例中悠夯,如果用戶界面處于雙面板模式下癌淮,那么點(diǎn)擊標(biāo)題列表中的標(biāo)題就會(huì)在右側(cè)面板中打開相應(yīng)報(bào)道;但如果用戶界面處于單面板模式下沦补,那么上述操作就會(huì)啟動(dòng)一個(gè)獨(dú)立活動(dòng):

@Override
public void onHeadlineSelected(int index) {
    mArtIndex = index;
    if (mIsDualPane) {
        /* display article on the right pane */
        mArticleFragment.displayArticle(mCurrentCat.getArticle(index));
    } else {
        /* start a separate activity */
        Intent intent = new Intent(this, ArticleActivity.class);
        intent.putExtra("catIndex", mCatIndex);
        intent.putExtra("artIndex", index);
        startActivity(intent);
    }
}
  • 步驟3:重復(fù)使用其他活動(dòng)中的片段
    多屏幕設(shè)計(jì)中的重復(fù)模式是指乳蓄,對(duì)于某些屏幕配置,已實(shí)施界面的一部分會(huì)用作面板夕膀;但對(duì)于其他配置虚倒,這部分就會(huì)以獨(dú)立活動(dòng)的形式存在。

例如产舞,在新聞閱讀器示例中魂奥,對(duì)于較大的屏幕,新聞報(bào)道文本會(huì)顯示在右側(cè)面板中易猫;但對(duì)于較小的屏幕耻煤,這些文本就會(huì)以獨(dú)立活動(dòng)的形式存在。

在類似情況下准颓,通彻可以在多個(gè)活動(dòng)中重復(fù)使用相同的 Fragment 子類以避免代碼重復(fù)。例如攘已,在雙面板布局中使用了 ArticleFragment:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="horizontal">
    <fragment android:id="@+id/headlines"
              android:layout_height="fill_parent"
              android:name="com.example.android.newsreader.HeadlinesFragment"
              android:layout_width="400dp"
              android:layout_marginRight="10dp"/>
    <fragment android:id="@+id/article"
              android:layout_height="fill_parent"
              android:name="com.example.android.newsreader.ArticleFragment"
              android:layout_width="fill_parent" />
</LinearLayout>

然后又在小屏幕的Activity布局中重復(fù)使用了它 :

ArticleFragment frag = new ArticleFragment();
getSupportFragmentManager().beginTransaction().add(android.R.id.content, frag).commit();
  • 步驟3:處理屏幕配置變化
    如果我們使用獨(dú)立Activity實(shí)施界面的獨(dú)立部分炮赦,那么請(qǐng)注意,我們可能需要對(duì)特定配置變化(例如屏幕方向的變化)做出響應(yīng)贯被,以便保持界面的一致性眼五。

例如,在運(yùn)行 Android 3.0 或更高版本的標(biāo)準(zhǔn) 7 英寸平板電腦上彤灶,如果新聞閱讀器示例應(yīng)用運(yùn)行在縱向模式下看幼,就會(huì)在使用獨(dú)立活動(dòng)顯示新聞報(bào)道;但如果該應(yīng)用運(yùn)行在橫向模式下幌陕,就會(huì)使用雙面板布局诵姜。

也就是說,如果用戶處于縱向模式下且屏幕上顯示的是用于閱讀報(bào)道的活動(dòng)搏熄,那么就需要在檢測(cè)到屏幕方向變化(變成橫向模式)后執(zhí)行相應(yīng)操作棚唆,即停止上述活動(dòng)并返回主活動(dòng)暇赤,以便在雙面板布局中顯示相關(guān)內(nèi)容:

public class ArticleActivity extends FragmentActivity {
    int mCatIndex, mArtIndex;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mCatIndex = getIntent().getExtras().getInt("catIndex", 0);
        mArtIndex = getIntent().getExtras().getInt("artIndex", 0);

        // If should be in two-pane mode, finish to return to main activity
        if (getResources().getBoolean(R.bool.has_two_panes)) {
            finish();
            return;
        }
        ...
}

通過上面一系列步驟,我們就完全可以建立一個(gè)可以根據(jù)用戶界面配置進(jìn)行自適應(yīng)的應(yīng)用程序App了宵凌。


總結(jié)

經(jīng)過上面的介紹鞋囊,對(duì)于屏幕尺寸大小適配問題應(yīng)該是不成問題了。


解決方案

  • 問題:如何進(jìn)行屏幕密度匹配瞎惫?
  • 答:
屏幕密度匹配解決方案.png

“布局控件”匹配

本質(zhì):使得布局組件在不同屏幕密度上顯示相同的像素效果

  • 做法1:使用密度無關(guān)像素
    由于各種屏幕的像素密度都有所不同溜腐,因此相同數(shù)量的像素在不同設(shè)備上的實(shí)際大小也有所差異,這樣使用像素(px)定義布局尺寸就會(huì)產(chǎn)生問題瓜喇。
    因此挺益,請(qǐng)務(wù)必使用密度無關(guān)像素 dp 或**獨(dú)立比例像素 sp **單位指定尺寸。
  • 相關(guān)概念介紹
    密度無關(guān)像素
  • 含義:density-independent pixel乘寒,叫dp或dip望众,與終端上的實(shí)際物理像素點(diǎn)無關(guān)。
  • 單位:dp伞辛,可以保證在不同屏幕像素密度的設(shè)備上顯示相同的效果
  1. Android開發(fā)時(shí)用dp而不是px單位設(shè)置圖片大小烂翰,是Android特有的單位
  2. 場(chǎng)景:假如同樣都是畫一條長(zhǎng)度是屏幕一半的線,如果使用px作為計(jì)量單位始锚,那么在480x800分辨率手機(jī)上設(shè)置應(yīng)為240px刽酱;在320x480的手機(jī)上應(yīng)設(shè)置為160px,二者設(shè)置就不同了瞧捌;如果使用dp為單位棵里,在這兩種分辨率下,160dp都顯示為屏幕一半的長(zhǎng)度姐呐。
  • dp與px的轉(zhuǎn)換
    因?yàn)閡i給你的設(shè)計(jì)圖是以px為單位的殿怜,Android開發(fā)則是使用dp作為單位的,那么該如何轉(zhuǎn)換呢曙砂?

| 密度類型 | 代表的分辨率(px) | 屏幕密度(dpi)|換算(px/dp) |比例|
| ------------- |:-------------:| -------------:| -------------:|
| 低密度(ldpi) | 240x320 | 120 |1dp=0.75px|3|
| 中密度(mdpi) | 320x480 | 160 |1dp=1px|4|
| 高密度(hdpi) | 480x800 | 240|1dp=1.5px|6|
| 超高密度(xhdpi) | 720x1280 | 320|1dp=2px|8|
| 超超高密度(xxhdpi) | 1080x1920 | 480 |1dp=3px|12|

在Android中头谜,規(guī)定以160dpi(即屏幕分辨率為320x480)為基準(zhǔn):1dp=1px

獨(dú)立比例像素

  • 含義:scale-independent pixel,叫sp或sip
  • 單位:sp
  1. Android開發(fā)時(shí)用此單位設(shè)置文字大小鸠澈,可根據(jù)用戶的偏好文字大小/字體大小首選項(xiàng)進(jìn)行縮放
  2. 推薦使用12sp柱告、14sp、18sp笑陈、22sp作為字體設(shè)置的大小际度,不推薦使用奇數(shù)和小數(shù),容易造成精度的丟失問題涵妥;小于12sp的字體會(huì)太小導(dǎo)致用戶看不清

所以乖菱,為了能夠進(jìn)行不同屏幕像素密度的匹配,我們推薦:

  • 使用dp來代替px作為控件長(zhǎng)度的統(tǒng)一度量單位
  • 使用sp作為文字的統(tǒng)一度量單位

可是,請(qǐng)看以下一種場(chǎng)景:

Nexus5的總寬度為360dp窒所,我們現(xiàn)在在水平方向上放置兩個(gè)按鈕鹉勒,一個(gè)是150dp左對(duì)齊,另外一個(gè)是200dp右對(duì)齊吵取,那么中間留有10dp間隔禽额;但假如同樣地設(shè)置在Nexus S(屏幕寬度是320dp),會(huì)發(fā)現(xiàn)海渊,兩個(gè)按鈕會(huì)重疊绵疲,因?yàn)?20dp<200+150dp

從上面可以看出哲鸳,由于Android屏幕設(shè)備的多樣性臣疑,如果使用dp來作為度量單位,并不是所有的屏幕的寬度都具備相同的dp長(zhǎng)度

再次明確徙菠,屏幕寬度和像素密度沒有任何關(guān)聯(lián)關(guān)系

所以說讯沈,dp解決了同一數(shù)值在不同分辨率中展示相同尺寸大小的問題(即屏幕像素密度匹配問題),但卻沒有解決設(shè)備尺寸大小匹配的問題婿奔。(即屏幕尺寸匹配問題)

當(dāng)然缺狠,我們一開始討論的就是屏幕尺寸匹配問題,使用match_parent萍摊、wrap_content和weight挤茄,盡可能少用dp來指定控件的具體長(zhǎng)寬,大部分的情況我們都是可以做到適配的冰木。

那么該如何解決控件的屏幕尺寸和屏幕密度的適配問題呢穷劈?

從上面可以看出:

  • 因?yàn)槠聊幻芏龋ǚ直媛剩┎灰粯樱圆荒苡霉潭ǖ膒x
  • 因?yàn)槠聊粚挾炔灰粯佑环校砸⌒牡挠胐p

因?yàn)楸举|(zhì)上是希望使得布局組件在不同屏幕密度上顯示相同的像素效果歇终,那么,之前是繞了個(gè)彎使用dp解決這個(gè)問題逼龟,那么到底能不能直接用px解決呢评凝?

即根據(jù)不同屏幕密度,控件選擇對(duì)應(yīng)的像素值大小

接下來介紹一種方法:百分比適配方法腺律,步驟如下:

  1. 以某一分辨率為基準(zhǔn)奕短,生成所有分辨率對(duì)應(yīng)像素?cái)?shù)列表
  2. 將生成像素?cái)?shù)列表存放在res目錄下對(duì)應(yīng)的values文件下
  3. 根據(jù)UI設(shè)計(jì)師給出設(shè)計(jì)圖上的尺寸,找到對(duì)應(yīng)像素?cái)?shù)的單位匀钧,然后設(shè)置給控件即可

步驟1:以某一分辨率為基準(zhǔn)翎碑,生成所有分辨率對(duì)應(yīng)像素?cái)?shù)列表

現(xiàn)在我們以320x480的分辨率為基準(zhǔn):

  • 將屏幕的寬度分為320份,取值為x1~x320
  • 將屏幕的高度分為480份榴捡,取值為y1~y480

然后生成該分辨率對(duì)應(yīng)像素?cái)?shù)的列表杈女,如下圖:

  • lay_x.xml(寬)
<?xml version="1.0" encoding="utf-8"?>
<resources><dimen name="x1">1.0px</dimen>
<dimen name="x2">2.0px</dimen>
<dimen name="x3">3.0px</dimen>
<dimen name="x4">4.0px</dimen>
<dimen name="x5">5.0px</dimen>
<dimen name="x6">6.0px</dimen>
<dimen name="x7">7.0px</dimen>
<dimen name="x8">8.0px</dimen>
<dimen name="x9">9.0px</dimen>
<dimen name="x10">10.0px</dimen>
...
<dimen name="x300">300.0px</dimen>
<dimen name="x301">301.0px</dimen>
<dimen name="x302">302.0px</dimen>
<dimen name="x303">303.0px</dimen>
<dimen name="x304">304.0px</dimen>
<dimen name="x305">305.0px</dimen>
<dimen name="x306">306.0px</dimen>
<dimen name="x307">307.0px</dimen>
<dimen name="x308">308.0px</dimen>
<dimen name="x309">309.0px</dimen>
<dimen name="x310">310.0px</dimen>
<dimen name="x311">311.0px</dimen>
<dimen name="x312">312.0px</dimen>
<dimen name="x313">313.0px</dimen>
<dimen name="x314">314.0px</dimen>
<dimen name="x315">315.0px</dimen>
<dimen name="x316">316.0px</dimen>
<dimen name="x317">317.0px</dimen>
<dimen name="x318">318.0px</dimen>
<dimen name="x319">319.0px</dimen>
<dimen name="x320">320px</dimen>
</resources>
  • lay_y.xml(高)
<?xml version="1.0" encoding="utf-8"?>
<resources><dimen name="y1">1.0px</dimen>
<dimen name="y2">2.0px</dimen>
<dimen name="y3">3.0px</dimen>
<dimen name="y4">4.0px</dimen>
...
<dimen name="y480">480px</dimen>
</resources>

找到基準(zhǔn)后,是時(shí)候把其他分辨率補(bǔ)全了,現(xiàn)今以寫1080x1920的分辨率為例:

因?yàn)榛鶞?zhǔn)是320x480达椰,所以1080/320=3.375px翰蠢,1920/480=4px,所以相應(yīng)文件應(yīng)該是

  • lay_x.xml
<?xml version="1.0" encoding="utf-8"?>
<resources><dimen name="x1">3.375px</dimen>
<dimen name="x2">6.65px</dimen>
<dimen name="x3">10.125px</dimen>
...
<dimen name="x320">1080px</dimen>
</resources>
  • lay_y.xml
<?xml version="1.0" encoding="utf-8"?>
<resources><dimen name="y1">4px</dimen>
<dimen name="y2">8px</dimen>
<dimen name="y3">12px</dimen>
<dimen name="y4">16px</dimen>
...
<dimen name="y480">1920px</dimen>
</resources>

用上面的方法把你需要適配的分辨率的像素列表補(bǔ)全吧~

作為程序猿的我們當(dāng)然不會(huì)做手寫的這些蠢事ⅰA翰住!多謝 @鴻洋大神 提供了自動(dòng)生成工具(內(nèi)置了常用的分辨率)蝇裤,大家可以直接點(diǎn)擊這里下載
注:工具默認(rèn)基準(zhǔn)為400*320廷支,當(dāng)然對(duì)于特殊需求,通過命令行指定即可:

java -jar 文件名.jar 基準(zhǔn)寬 基準(zhǔn)高 額外支持尺寸1的寬栓辜,額外支持尺寸1的高_(dá)額外支持尺寸2的寬,額外支持尺寸2的高:

例如:需要設(shè)置的基準(zhǔn)是800x1280恋拍,額外支持尺寸:735x1152 ;3200x4500藕甩;

java -jar 文件名.jar 800 1280 735施敢,1152_3200,4500

步驟2:把生成的各像素?cái)?shù)列表放到對(duì)應(yīng)的資源文件

將生成像素?cái)?shù)列表(lay_x.xml和lay_y.xml)存放在res目錄下對(duì)應(yīng)的values文件(注意寬、高要對(duì)應(yīng))狭莱,如下圖:

res目錄下對(duì)應(yīng)的values文件

注:

  • 分辨率為480x320的資源文件應(yīng)放在res/values-480x320文件夾中僵娃;同理分辨率為1920x1080的資源文件應(yīng)放在res/values-1920x1080文件夾中。(其中values-480x320是分辨率限定符)
  • 必須在默認(rèn)values里面也創(chuàng)建對(duì)應(yīng)默認(rèn)lay_x.xml和lay_y.xml文件腋妙,如下圖
    lay_x.xml
<?xml version="1.0" encoding="utf-8">
<resources>
<dimen name="x1">1.0dp</dimen>
<dimen name="x2">2.0dp</dimen>
...
</resources>
  • 因?yàn)閷?duì)于沒有生成對(duì)應(yīng)分辨率文件的手機(jī)默怨,會(huì)使用默認(rèn)values文件夾,如果默認(rèn)values文件夾沒有(即沒有對(duì)應(yīng)的分辨率骤素、沒有對(duì)應(yīng)dimen)就會(huì)報(bào)錯(cuò)匙睹,從而無法進(jìn)行屏幕適配。
    注意對(duì)應(yīng)單位改為dp谆甜,而不同于上面的px垃僚。因?yàn)椴恢罊C(jī)型的分辨率,所以默認(rèn)分辨率文件只好默認(rèn)為x1=1dp以保證盡量兼容(又回到dp老方法了)规辱,這也是這個(gè)解決方案的一個(gè)弊端

步驟3:根據(jù)UI設(shè)計(jì)師給出某一分辨率設(shè)計(jì)圖上的尺寸谆棺,找到對(duì)應(yīng)像素?cái)?shù)的單位,然后設(shè)置給控件即可

如下圖:

<FrameLayout >

    <Button
        android:layout_gravity="center"
        android:gravity="center"
        android:text="@string/hello_world"
        android:layout_width="@dimen/x160"
        android:layout_height="@dimen/y160"/>

</FrameLayout>

總結(jié)

使用上述的適配方式罕袋,應(yīng)該能進(jìn)行90%的適配了改淑,但其缺點(diǎn)還是很明顯:

  • 由于實(shí)際上還是使用px作為長(zhǎng)度的度量單位,所以和google的要求使用dp作為度量單位會(huì)有所背離
  • 必須盡可能多的包含所有分辨率浴讯,因?yàn)檫@個(gè)是使用這個(gè)方案的基礎(chǔ)朵夏,如果有某個(gè)分辨率缺少,將無法完成該屏幕的適配
  • 過多的分辨率像素描述xml文件會(huì)增加軟件包的大小和維護(hù)的難度

“圖片資源”匹配

本質(zhì):使得圖片資源在不同屏幕密度上顯示相同的像素效果

  • 做法:提供備用位圖(符合屏幕尺寸的圖片資源)
    由于 Android 可在各種屏幕密度的設(shè)備上運(yùn)行榆纽,因此我們提供的位圖資源應(yīng)該始終可以滿足各類密度的要求:
密度類型 代表的分辨率(px) 系統(tǒng)密度(dpi)
低密度(ldpi) 240x320 120
中密度(mdpi) 320x480 160
高密度(hdpi) 480x800 240
超高密度(xhdpi) 720x1280 320
超超高密度(xxhdpi) 1080x1920 480
  • 步驟1:根據(jù)以下尺寸范圍針對(duì)各密度生成相應(yīng)的圖片仰猖。

比如說捏肢,如果我們?yōu)?xhdpi 設(shè)備生成了 200x200 px尺寸的圖片,就應(yīng)該按照相應(yīng)比例地為 hdpi饥侵、mdpi 和 ldpi 設(shè)備分別生成 150x150鸵赫、100x100 和 75x75 尺寸的圖片

即一套分辨率=一套位圖資源(這個(gè)當(dāng)然是Ui設(shè)計(jì)師做了)

  • 步驟2:將生成的圖片文件放在 res/ 下的相應(yīng)子目錄中(mdpi、hdpi躏升、xhdpi辩棒、xxhdpi),系統(tǒng)就會(huì)根據(jù)運(yùn)行您應(yīng)用的設(shè)備的屏幕密度自動(dòng)選擇合適的圖片
  • 步驟3:通過引用 @drawable/id膨疏,系統(tǒng)都能根據(jù)相應(yīng)屏幕的 屏幕密度(dpi)自動(dòng)選取合適的位圖一睁。

注:

  • 如果是.9圖或者是不需要多個(gè)分辨率的圖片,放在drawable文件夾即可
  • 對(duì)應(yīng)分辨率的圖片要正確的放在合適的文件夾佃却,否則會(huì)造成圖片拉伸等問題者吁。

更好地方案解決“圖片資源”適配問題

上述方案是常見的一種方案,這固然是一種解決辦法双霍,但缺點(diǎn)在于:

  • 每套分辨率出一套圖砚偶,為美工或者設(shè)計(jì)增加了許多工作量
  • 對(duì)Android工程文件的apk包變的很大

那么,有沒有一種方法:

  • 保證屏幕密度適配
  • 可以最小占用設(shè)計(jì)資源
  • 使得apk包不變大(只使用一套分辨率的圖片資源)

下面我們就來介紹這個(gè)方法

  • 只需選擇唯一一套分辨率規(guī)格的圖片資源

方法介紹

1. 先來理解下Android 加載資源過程
Android SDK會(huì)根據(jù)屏幕密度自動(dòng)選擇對(duì)應(yīng)的資源文件進(jìn)行渲染加載(自動(dòng)渲染)

比如說洒闸,SDK檢測(cè)到你手機(jī)的分辨率是320x480(dpi=160),會(huì)優(yōu)先到drawable-mdpi文件夾下找對(duì)應(yīng)的圖片資源均芽;但假設(shè)你只在xhpdi文件夾下有對(duì)應(yīng)的圖片資源文件(mdpi文件夾是空的)丘逸,那么SDK會(huì)去xhpdi文件夾找到相應(yīng)的圖片資源文件,然后將原有大像素的圖片自動(dòng)縮放成小像素的圖片掀宋,于是大像素的圖片照樣可以在小像素分辨率的手機(jī)上正常顯示深纲。
具體請(qǐng)看http://blog.csdn.net/xiebudong/article/details/37040263

所以理論上來說只需要提供一種分辨率規(guī)格的圖片資源就可以了
那么應(yīng)該提供哪種分辨率規(guī)格呢梦抢?

如果只提供ldpi規(guī)格的圖片厌秒,對(duì)于大分辨率(xdpi夺颤、xxdpi)的手機(jī)如果把圖片放大就會(huì)不清晰

所以需要提供一套你需要支持的最大dpi分辨率規(guī)格的圖片資源,這樣即使用戶的手機(jī)分辨率很小币呵,這樣圖片縮小依然很清晰。那么這一套最大dpi分辨率規(guī)格應(yīng)該是哪種呢侨颈?是現(xiàn)在市面手機(jī)分辨率最大可達(dá)到1080X1920的分辨率(dpi=xxdpi=480)嗎余赢?

2. xhdpi應(yīng)該是首選

原因如下:

  • xhdpi分辨率以內(nèi)的手機(jī)需求量最旺盛
    目前市面上最普遍的高端機(jī)的分辨率還多集中在720X1080范圍內(nèi)(xhdpi),所以目前來看xhpdi規(guī)格的圖片資源成為了首選
  • 節(jié)省設(shè)計(jì)資源&工作量
    在現(xiàn)在的App開發(fā)中(iOS和Android版本)哈垢,有些設(shè)計(jì)師為了保持App不同版本的體驗(yàn)交互一致妻柒,可能會(huì)以iPhone手機(jī)為基礎(chǔ)進(jìn)行設(shè)計(jì),包括后期的切圖之類的耘分。
    設(shè)計(jì)師們一般都會(huì)用最新的iPhone6和iPhone5s(5s和5的尺寸以及分辨率都一樣)來做原型設(shè)計(jì)举塔,所有參數(shù)請(qǐng)看下圖
機(jī)型 分辨率(px) 屏幕尺寸(inch) 系統(tǒng)密度(dpi)
iPhone 5s 640X1164 4 332
iPhone 6 1334x750 4.7 326
iPhone 6 Plus 1080x1920 5 400

iPhone主流的屏幕dpi約等于320, 剛好屬于xhdpi绑警,所以選擇xhdpi作為唯一一套dpi圖片資源,可以讓設(shè)計(jì)師不用專門為Android端切圖央渣,直接把iPhone的那一套切好的圖片資源放入drawable-xhdpi文件夾里就好待秃,這樣大大減少的設(shè)計(jì)師的工作量!

額外小tips

  • ImageView的ScaleType屬性
    設(shè)置不同的ScaleType會(huì)得到不同的顯示效果痹屹,一般情況下章郁,設(shè)置為centerCrop能獲得較好的適配效果。

  • 動(dòng)態(tài)設(shè)置

使用場(chǎng)景:有些情況下志衍,我們需要?jiǎng)討B(tài)的設(shè)置控件大小或者是位置暖庄,比如說popwindow的顯示位置和偏移量等

這時(shí)我們可以動(dòng)態(tài)獲取當(dāng)前的屏幕屬性,然后設(shè)置合適的數(shù)值

public class ScreenSizeUtil { 
  public static int getScreenWidth(Activity activity) { 
    return activity.getWindowManager().getDefaultDisplay().getWidth(); 
} 
  public static int getScreenHeight(Activity activity) { 
    return activity.getWindowManager().getDefaultDisplay().getHeight(); 
   }
}

總結(jié)

  • 本文根據(jù)現(xiàn)今主流Android的適配方法楼肪,以邏輯清晰的方式進(jìn)行了主流Android適配方法的全面整理
  • 下面我將繼續(xù)對(duì) Android中的知識(shí)進(jìn)行深入講解培廓,感興趣的同學(xué)可以繼續(xù)關(guān)注Carson_Ho的簡(jiǎn)書

相關(guān)系列文章閱讀
Carson帶你學(xué)Android:學(xué)習(xí)方法
Carson帶你學(xué)Android:四大組件
Carson帶你學(xué)Android:自定義View
Carson帶你學(xué)Android:異步-多線程
Carson帶你學(xué)Android:性能優(yōu)化
Carson帶你學(xué)Android:動(dòng)畫


歡迎關(guān)注Carson_Ho的簡(jiǎn)書

不定期分享關(guān)于安卓開發(fā)的干貨,追求短春叫、平肩钠、快,但卻不缺深度暂殖。


請(qǐng)點(diǎn)贊价匠!因?yàn)槟愕墓膭?lì)是我寫作的最大動(dòng)力!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末呛每,一起剝皮案震驚了整個(gè)濱河市踩窖,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌晨横,老刑警劉巖洋腮,帶你破解...
    沈念sama閱讀 206,126評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異手形,居然都是意外死亡啥供,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門库糠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來伙狐,“玉大人,你說我怎么就攤上這事曼玩×壑瑁” “怎么了?”我有些...
    開封第一講書人閱讀 152,445評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵黍判,是天一觀的道長(zhǎng)豫尽。 經(jīng)常有香客問我,道長(zhǎng)顷帖,這世上最難降的妖魔是什么美旧? 我笑而不...
    開封第一講書人閱讀 55,185評(píng)論 1 278
  • 正文 為了忘掉前任渤滞,我火速辦了婚禮,結(jié)果婚禮上榴嗅,老公的妹妹穿的比我還像新娘妄呕。我一直安慰自己,他們只是感情好嗽测,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評(píng)論 5 371
  • 文/花漫 我一把揭開白布绪励。 她就那樣靜靜地躺著,像睡著了一般唠粥。 火紅的嫁衣襯著肌膚如雪疏魏。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,970評(píng)論 1 284
  • 那天晤愧,我揣著相機(jī)與錄音大莫,去河邊找鬼。 笑死官份,一個(gè)胖子當(dāng)著我的面吹牛只厘,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播舅巷,決...
    沈念sama閱讀 38,276評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼羔味,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了悄谐?” 一聲冷哼從身側(cè)響起介评,我...
    開封第一講書人閱讀 36,927評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎爬舰,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體寒瓦,經(jīng)...
    沈念sama閱讀 43,400評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡情屹,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了杂腰。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片垃你。...
    茶點(diǎn)故事閱讀 37,997評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖喂很,靈堂內(nèi)的尸體忽然破棺而出惜颇,到底是詐尸還是另有隱情,我是刑警寧澤少辣,帶...
    沈念sama閱讀 33,646評(píng)論 4 322
  • 正文 年R本政府宣布凌摄,位于F島的核電站,受9級(jí)特大地震影響漓帅,放射性物質(zhì)發(fā)生泄漏锨亏。R本人自食惡果不足惜痴怨,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望器予。 院中可真熱鬧浪藻,春花似錦、人聲如沸乾翔。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽反浓。三九已至萌丈,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間勾习,已是汗流浹背浓瞪。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評(píng)論 1 260
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留巧婶,地道東北人乾颁。 一個(gè)月前我還...
    沈念sama閱讀 45,423評(píng)論 2 352
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像艺栈,于是被迫代替她去往敵國和親英岭。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評(píng)論 2 345

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