Android屏幕適配姿勢

GitHub地址

ScreenAdaptDemo

為什么要屏幕適配?

device_framentation.png

統(tǒng)計

碎片化

  • 品牌機(jī)型碎片化
  • 屏幕尺寸碎片化
  • 操作系統(tǒng)碎片化

為了保證用戶獲得一致的用戶體驗效果箱残,使得某一元素在Android不同尺寸、不同分辨率的手機(jī)上具備相同的顯示效果止吁,則需要我們進(jìn)行屏幕適配被辑。

基礎(chǔ)概念

屏幕尺寸

屏幕尺寸是指屏幕對角線的長度,單位是英寸敬惦,1 inch=2.54 cm

屏幕分辨率

手機(jī)在橫向和縱向上的像素點數(shù)總和盼理,單位是像素(pixel),1px = 1像素點俄删,舉個栗子宏怔,1080x1920豪诲,即寬度方向上有1080個像素點矮嫉,在高度方向上有1920個像素點。

屏幕像素密度

每英寸像素點個數(shù)状原,單位是dpi斜脂,dots per inch抓艳。為簡便起見,Android 將所有屏幕密度分組為六種通用密度: 低秽褒、中壶硅、高、超高销斟、超超高和超超超高庐椒。

  • ldpi(低)~120dpi
  • mdpi(中)~160dpi
  • hdpi(高)~240dpi
  • xhdpi(超高)~320dpi
  • xxhdpi(超超高)~480dpi
  • xxxhdpi(超超超高)~640dpi
dpi_example.png

屏幕密度無關(guān)像素dp(dip)

Density Independent Pixels,即密度無關(guān)像素蚂踊。

  • 160dpi, 1dp = 1px
  • 240dpi, 1dp = 1.5px
  • 320dpi, 1dp = 2px
  • 480dpi, 1dp = 3px
  • 640dpi, 1dp = 4px

使用px在低约谈、中、高屏幕密度下的效果###

density-test-bad.png

使用dp在低犁钟、中棱诱、高屏幕密度下的效果

density-test-good.png

獨立比例像素sp

Scale Independent Pixels, 即sp或sip。
Android開發(fā)時用此單位設(shè)置文字大小涝动,可根據(jù)字體大小首選項進(jìn)行縮放迈勋,推薦使用12sp、14sp醋粟、18sp靡菇、22sp作為字體設(shè)置的大小重归,不推薦使用奇數(shù)和小數(shù),容易造成精度的丟失問題,小于12sp的字體會太小導(dǎo)致用戶看不清厦凤。

屏幕適配之圖片適配

screens-densities.png

在設(shè)計圖標(biāo)時鼻吮,對于5種主流的像素密度(mdpi,hdpi,xhdpi,xxhdpi和xxxdpi)應(yīng)按照2:3:4:6:8的比例進(jìn)行縮放。例如一個啟動圖片ic_launcher.png,它在各個像素密度文件夾下大小為:

  • ldpi(低)
  • mdpi(中)48*48
  • hdpi(高)72*72
  • xhdpi(超高)96*96
  • xxhdpi(超超高)144*144
  • xxxhdpi(超超超高)192*192

存在的問題

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

解決方法

Android SDK加載圖片流程

  1. Android SDK會根據(jù)屏幕密度自動選擇對應(yīng)的資源文件進(jìn)行渲染加載椎木,比如說,SDK檢測到你手機(jī)的分辨率是xhdpi博烂,會優(yōu)先到xhdpi文件夾下找對應(yīng)的圖片資源香椎;
  2. 如果xhdpi文件夾下沒有圖片資源,那么就會去分辨率高的文件夾下查找脖母,比如xxhdpi士鸥,直到找到同名圖片資源,將它按比例縮小成xhpi圖片谆级;
  3. 如果往上查找圖片還是沒有找到烤礁,那么就會往低分辨率的文件夾查找,比如hdpi肥照,直到找到同名圖片資源脚仔,將它按比例放大成xhpi圖片。

根據(jù)加載圖片的流程舆绎,可以得出理論上提供一套圖片就可以了鲤脏。

那么應(yīng)該提供哪種分辨率規(guī)格呢?###

原則上越高越好吕朵,同時結(jié)合當(dāng)前主流分辨率屏幕

自動拉伸圖片

ninepatch_raw.png
ninepatch_examples.png

屏幕適配之布局適配

布局參數(shù)

使用wrap_content, match_parent, layout_weight猎醇。

weight的使用

weight_examples.png
  • 當(dāng)layout_width為0dp,layout_weight分別是1和2

      <LinearLayout
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:orientation="horizontal">
    
          <Button
              android:layout_width="0dp"
              android:layout_height="wrap_content"
              android:layout_weight="1"
              android:text="weight = 1"/>
    
          <Button
              android:layout_width="0dp"
              android:layout_height="wrap_content"
              android:layout_weight="2"
              android:text="weight = 2"/>
      </LinearLayout>
    
  • 當(dāng)layout_width為match_parent,layout_weight分別為1和2

      <LinearLayout
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:orientation="horizontal">
    
          <Button
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:layout_weight="1"
              android:text="weight = 1"/>
    
          <Button
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:layout_weight="2"
              android:text="weight = 2"/>
      </LinearLayout>
    

weight的計算

寬度 = 原來寬度 + 權(quán)重比值 * 剩余寬度

  • 當(dāng)layout_width為0dp努溃,layout_weight分別是1和2

    第一個按鈕:寬度 = 0 + 1/3 * 屏寬 = 1/3屏寬

    第二個按鈕:寬度 = 0 + 2/3 * 屏寬 = 2/3屏寬

  • 當(dāng)layout_width為match_parent, layout_weight分別是1和2

    第一個按鈕:寬度 = 屏寬 + 1/3 * (屏寬 - 2 * 屏寬) = 2/3屏寬

    第二個按鈕:寬度 = 屏寬 + 2/3 * (屏寬 - 2 * 屏寬) = 1/3屏寬

布局使用

使用相對布局硫嘶,禁用絕對布局。

限定符

尺寸限定符

  • 在手機(jī)較小的屏幕上梧税,加載layout文件夾布局
  • 在平板電腦和電視的屏幕(>7英寸)上沦疾, 加載layout-large文件夾的布局
  • Android3.2版本之前

最小寬度限定符

  • 在手機(jī)較小的屏幕上,加載layout文件夾布局
  • 標(biāo)準(zhǔn)7英寸平板(其最小寬度為 600 dp)第队,加載layout-sw600dp文件夾的布局
  • 在Android3.2版本及之后版本

布局別名

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

最后的兩個文件的xml內(nèi)容是完全相同的哮塞,這會帶來:文件名的重復(fù)從而帶來一些列后期維護(hù)的問題,修改一個文件凳谦,可能忘記修改另外一個忆畅。于是為了要解決這種重復(fù)問題,我們引入了布局別名尸执。

  • 適配手機(jī)的單面板(默認(rèn))布局:res/layout/activity_main.xml

  • 適配尺寸>7寸平板的雙面板布局:res/layout/activity_twopanes.xml

  • res/values/layout.xml

      <?xml version="1.0" encoding="utf-8"?>
      <resources>
          <item name="main" type="layout">@layout/activity_main</item>
      </resources>
    
  • res/values-large/layout.xml

      <?xml version="1.0" encoding="utf-8"?>
      <resources>
          <item name="main" type="layout">@layout/activity_twopanes</item>
      </resources>
    
  • res/values-sw600dp/layout.xml

      <?xml version="1.0" encoding="utf-8"?>
      <resources>
          <item name="main" type="layout">@layout/activity_twopanes</item>
      </resources>
    
  • setContentView(R.layout.main);

屏幕方向限定符

  • res/layout-land
  • res/layout-port
  • res/layout-sw600dp-land
  • res/layout-sw600dp-port

屏幕適配之dimen適配

  • Nexus 4 (4.7英寸 768x1280:xhdpi)
dimen_example1.png
  • Nexus S (4英寸 480x800:hdpi)
dimen_example2.png

即使使用dp邻眷,依然不能解決屏幕分辨率的適配問題眠屎,我們可以針對不同的屏幕創(chuàng)建不同的dimen值。

  • res/values/dimens.xml

      <resources>
      <dimen name="button_length_1">180dp</dimen>
      <dimen name="button_length_2">160dp</dimen>
      </resources>
    
  • res/values-480x800/dimens.xml

      <resources>
          <dimen name="button_length_1">113dp</dimen>
          <dimen name="button_length_2">100dp</dimen>
      </resources>
    

屏幕適配之百分比布局

  • 官方文檔

  • Github Sample

      <?xml version="1.0" encoding="utf-8"?>
      <android.support.percent.PercentRelativeLayout
          xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:app="http://schemas.android.com/apk/res-auto"
          android:layout_width="match_parent"
          android:layout_height="wrap_content">
      
          <Button
              android:layout_width="0dp"
              android:layout_height="wrap_content"
              android:text="30%"
              app:layout_widthPercent="30%"/>
      
          <Button
              android:layout_width="0dp"
              android:layout_height="wrap_content"
              android:layout_alignParentRight="true"
              android:text="20%"
              app:layout_widthPercent="20%"/>
      
      </android.support.percent.PercentRelativeLayout>
    

屏幕適配之自適應(yīng)用戶界面

newsreader_land.png
newsreader_port.png

當(dāng)NewsReader在橫屏?xí)r是雙面板肆饶,左側(cè)是HeadLinesFragment, 右側(cè)是ArticleFragment, 點擊新聞標(biāo)題, 切換ArticleFragment的內(nèi)容。當(dāng)NewsReader在豎屏?xí)r是單面板岖常,只有個HeadLinesFragment, 點擊新聞標(biāo)題驯镊,跳轉(zhuǎn)到ArticleActivity去顯示新聞內(nèi)容。所以竭鞍,要實現(xiàn)這樣的橫豎屏適配板惑,只是通過布局是完成不了的,不同業(yè)務(wù)邏輯的處理偎快,還需要寫代碼來完成冯乘,這就是我們的自適應(yīng)用戶界面。

使用布局別名

  • res/values/layouts.xml

      <resources>
      <item name="main_layout" type="layout">@layout/onepane_with_bar</item>
      <bool name="has_two_panes">false</bool>
      </resources>
    
  • res/values-sw600dp-land/layouts.xml

      <resources>
      <item name="main_layout" type="layout">@layout/twopanes</item>
      <bool name="has_two_panes">true</bool>
      </resources>
    
  • res/values-sw600dp-port/layouts.xml

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

判斷是單面板還是雙面板

View articleView = findViewById(R.id.article);
mIsDualPane = articleView != null && articleView.getVisibility() == View.VISIBLE;//如果能夠找到ArticleFragment則是雙面板

單雙面板的不同業(yè)務(wù)邏輯

public void onHeadlineSelected(int index) {
    mArtIndex = index;
    if (mIsDualPane) {
        // display it on the article fragment
        mArticleFragment.displayArticle(mCurrentCat.getArticle(index));
    }
    else {
        // use separate activity
        Intent i = new Intent(this, ArticleActivity.class);
        i.putExtra("catIndex", mCatIndex);
        i.putExtra("artIndex", index);
        startActivity(i);
    }
}

參考

本文部分文字和圖片直接摘錄自以下內(nèi)容:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末裆馒,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子丐怯,更是在濱河造成了極大的恐慌喷好,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,591評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件读跷,死亡現(xiàn)場離奇詭異梗搅,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)效览,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評論 3 392
  • 文/潘曉璐 我一進(jìn)店門无切,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人丐枉,你說我怎么就攤上這事哆键。” “怎么了矛洞?”我有些...
    開封第一講書人閱讀 162,823評論 0 353
  • 文/不壞的土叔 我叫張陵洼哎,是天一觀的道長。 經(jīng)常有香客問我沼本,道長噩峦,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,204評論 1 292
  • 正文 為了忘掉前任抽兆,我火速辦了婚禮识补,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘辫红。我一直安慰自己凭涂,他們只是感情好祝辣,可當(dāng)我...
    茶點故事閱讀 67,228評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著切油,像睡著了一般蝙斜。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上澎胡,一...
    開封第一講書人閱讀 51,190評論 1 299
  • 那天孕荠,我揣著相機(jī)與錄音,去河邊找鬼攻谁。 笑死稚伍,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的个曙。 我是一名探鬼主播,決...
    沈念sama閱讀 40,078評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼受楼,長吁一口氣:“原來是場噩夢啊……” “哼垦搬!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起那槽,我...
    開封第一講書人閱讀 38,923評論 0 274
  • 序言:老撾萬榮一對情侶失蹤悼沿,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后骚灸,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體糟趾,經(jīng)...
    沈念sama閱讀 45,334評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,550評論 2 333
  • 正文 我和宋清朗相戀三年甚牲,在試婚紗的時候發(fā)現(xiàn)自己被綠了义郑。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,727評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡丈钙,死狀恐怖非驮,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情雏赦,我是刑警寧澤劫笙,帶...
    沈念sama閱讀 35,428評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站星岗,受9級特大地震影響填大,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜俏橘,卻給世界環(huán)境...
    茶點故事閱讀 41,022評論 3 326
  • 文/蒙蒙 一允华、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦靴寂、人聲如沸磷蜀。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽褐隆。三九已至,卻和暖如春收壕,著一層夾襖步出監(jiān)牢的瞬間妓灌,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評論 1 269
  • 我被黑心中介騙來泰國打工蜜宪, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人祥山。 一個月前我還...
    沈念sama閱讀 47,734評論 2 368
  • 正文 我出身青樓圃验,卻偏偏與公主長得像,于是被迫代替她去往敵國和親缝呕。 傳聞我的和親對象是個殘疾皇子澳窑,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,619評論 2 354

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