屏幕適配經(jīng)驗(二)

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

  • 使得“布局”优构、“布局組件”、“圖片資源”雁竞、“用戶界面流程”匹配不同的屏幕尺寸

  • 使得布局钦椭、布局組件自適應(yīng)屏幕尺寸;

  • 根據(jù)屏幕的配置來加載相應(yīng)的UI布局、用戶界面流程

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

解決方案

1:使得布局元素自適應(yīng)屏幕尺寸
開發(fā)中彪腔,我們使用的布局一般有:

  • 線性布局(Linearlayout)
  • 相對布局(RelativeLayout)
  • 幀布局(FrameLayout)
  • 表格布局(TabLayout)
  • 絕對布局(AbsoluteLayout)

常用的就是線性布局(Linearlayout)侥锦、相對布局(RelativeLayout)和幀布局(FrameLayout)需要根據(jù)需求進行選擇,但要記椎抡酢:

  • RelativeLayout
    布局的子控件之間使用相對位置的方式排列捎拯,因為RelativeLayout講究的是相對位置,即使屏幕的大小改變盲厌,視圖之前的相對位置都不會變化,與屏幕大小無關(guān)祸泪,靈活性很強

  • LinearLayout
    通過多層嵌套LinearLayout和組合使
    用"wrap_content"和"match_parent"以及"weight"來構(gòu)建布局吗浩。但是LinearLayout無法準確地控制子視圖之間的位置關(guān)系,只能簡單的一個挨著一個地排列

所以没隘,對于屏幕適配來說懂扼,使用相對布局(RelativeLayout)將會是更好的解決方案

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

做法:使用限定符

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

  • 作用:通過配置限定符使得程序在運行時根據(jù)當前設(shè)備的配置(屏幕尺寸)自動加載合適的布局資源
    。限定符類型:
    右蒲。尺寸(size)限定符
    阀湿。最小寬度(Smallest-width)限定符
    。布局別名
    瑰妄。屏幕方向(Orientation)限定符

尺寸(size)限定符

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

因此,我們可以使用尺寸限定符(layout-large)通過創(chuàng)建一個文件來完成上述設(shè)定:

res/layout-large/main.xml
  • 讓系統(tǒng)在屏幕尺寸>7英寸時采用適配平板的雙面板布局
  • 反之(默認情況下)采用適配手機的單面板布局
    文件配置如下:

  • 適配手機的單面板(默認)布局: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>

注意:
1.兩個布局名稱均為main.xml间坐,只有布局的目錄名不同:第一個布局的目錄名為:layout灾挨,第二個布局的目錄名為:layout-large,包含了尺寸限定符(large)

2.被定義為大屏的設(shè)備(7寸以上的平板)會自動加載包含了large限定符目錄的布局竹宋,而小屏設(shè)備會加載另一個默認的布局

但要注意的是劳澄,這種方式只適合Android 3.2版本之前。

于是3.2之后推出了最小寬度(Smallest-width)限定符

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

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

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

  • 使用場景

你需要為標準 7 英寸平板電腦匹配雙面板布局(其最小寬度為 600 dp),在手機(較小的屏幕上)匹配單面板布局

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

  • sw xxxdp尽棕,即small width的縮寫喳挑,其不區(qū)分方向,即無論是寬度還是高度,只要大于 xxxdp伊诵,就采用次此布局
  • 例子:使用了layout-sw 600dp的最小寬度限定符单绑,即無論是寬度還是高度,只要大于600dp曹宴,就采用layout-sw 600dp目錄下的布局

例子

  • 適配手機的單面板(默認)布局: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>

對于最小寬度≥ 600 dp 的設(shè)備搂橙,系統(tǒng)會自動加載 layout-sw600dp/main.xml(雙面板)布局,否則系統(tǒng)就會選擇 layout/main.xml(單面板)布局(這個選擇過程是Android系統(tǒng)自動選擇的)

然而笛坦,使用早于Android 3.2系統(tǒng)的設(shè)備將無法識別sw600dp這個限定符区转,所以你還是同時需要使用large限定符。這樣你就需要在res/layout-large和res/layout-sw600dp目錄下都添加一個相同的main.xml版扩。

使用布局別名(也就是最后的解決辦法)

Smallest-width限定符僅在Android 3.2及之后的系統(tǒng)中有效废离。因而,你也需要同時使用Size限定符(small, normal, large和xlarge)來兼容更早的系統(tǒng)礁芦。例如蜻韭,你想手機上顯示single-pane界面,而在7寸平板和更大屏的設(shè)備上顯示multi-pane界面柿扣,你需要提供以下文件:

  • res/layout/main.xml: single-pane布局
  • res/layout-large: multi-pane布局
  • res/layout-sw600dp: multi-pane布局

最后的兩個文件是完全相同的肖方,為了要解決這種重復(fù),你需要使用別名技巧未状。例如俯画,你可以定義以下布局:

  • 適配手機的單面板(默認)布局 :res/layout/main.xml, single-pane布局
  • 適配尺寸>7寸平板的雙面板布局: res/layout/main_twopanes.xml, two-pane布局

然后加入以下兩個文件,以便進行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>

2.res/values-sw600dp/layout.xml(Android 3.2及之后的雙面板布局)

<resources>
<item name="main" type="layout">@layout/main_twopanes</item>
</resources>
  • 最后兩個文件有著相同的內(nèi)容司草,但是它們并沒有真正去定義布局活翩,它們僅僅只是給main定義了一個別名main_twopanes。這樣兩個layout.xml都只是引用了@layout/main_twopanes翻伺,就避免了重復(fù)定義布局文件的情況材泄。
  • 由于這些文件包含 large 和 sw600dp 選擇器,因此吨岭,系統(tǒng)會將此文件匹配到不同版本的>7寸平板上:
    a. 版本低于 3.2 的平板會匹配 large的文件
    b. 版本高于 3.2 的平板會匹配 sw600dp的文件

屏幕方向(Orientation)限定符

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

小屏幕, 豎屏: 單面板
小屏幕, 橫屏: 單面板
7 英寸平板電腦拉宗,縱向:單面板,帶操作欄
7 英寸平板電腦辣辫,橫向:雙面板旦事,寬,帶操作欄
10 英寸平板電腦急灭,縱向:雙面板姐浮,窄,帶操作欄
10 英寸平板電腦葬馋,橫向:雙面板卖鲤,寬肾扰,帶操作欄
電視,橫向:雙面板蛋逾,寬集晚,帶操作欄

分2步來完成:

1.先定義類別:單/雙面板、是否帶操作欄区匣、寬/窄

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

2.再進行相應(yīng)的匹配:屏幕尺寸(小屏偷拔、7寸、10寸)亏钩、方向(橫莲绰、縱)

使用布局別名進行匹配

具體

1.在 res/layout/ 目錄下的某個 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.使用布局別名進行相應(yīng)的匹配(屏幕尺寸(小屏彻坛、7寸、10寸)踏枣、方向(橫昌屉、縱)),可為resources設(shè)置bool,通過獲取其值來動態(tài)判斷目前已處在哪個適配布局

  • 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(大屏茵瀑、橫向间驮、雙面板、寬-Andorid 3.2版本后)
<resources>
    <item name="main_layout" type="layout">@layout/twopanes</item>
    <bool name="has_two_panes">true</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>

使用自動拉伸位圖:Nine-Patch的圖片類型(也就是我們常說的.9png圖片)

支持不同屏幕大小通常情況下也意味著,你的圖片資源也需要有自適應(yīng)的能力匙奴。例如堆巧,一個按鈕的背景圖片必須能夠隨著按鈕大小的改變而改變。
如果你想使用普通的圖片來實現(xiàn)上述功能泼菌,你很快就會發(fā)現(xiàn)結(jié)果是令人失望的谍肤,因為運行時會均勻地拉伸或壓縮你的圖片。解決方案是使用nine-patch圖片哗伯,它是一種被特殊處理過的PNG圖片荒揣,你可以指定哪些區(qū)域可以拉伸而哪些區(qū)域不可以。
因而焊刹,當你設(shè)計需要在不同大小的控件中使用的圖片時系任,最好的方法就是用nine-patch圖片

注意:

  • 必須要使用.9.png后綴名恳蹲,因為系統(tǒng)就是根據(jù)這個來區(qū)別nine-patch圖片和普通的PNG圖片的;
  • 必須放在drawable下面
  • 當你需要在一個控件中使用nine-patch圖片時,如
    android:background="@drawable/button"系統(tǒng)就會根據(jù)控件的大小自動地拉伸你想要拉伸的部分
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末赋除,一起剝皮案震驚了整個濱河市阱缓,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌举农,老刑警劉巖荆针,帶你破解...
    沈念sama閱讀 212,816評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異颁糟,居然都是意外死亡航背,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評論 3 385
  • 文/潘曉璐 我一進店門棱貌,熙熙樓的掌柜王于貴愁眉苦臉地迎上來玖媚,“玉大人,你說我怎么就攤上這事婚脱〗衲В” “怎么了?”我有些...
    開封第一講書人閱讀 158,300評論 0 348
  • 文/不壞的土叔 我叫張陵障贸,是天一觀的道長错森。 經(jīng)常有香客問我,道長篮洁,這世上最難降的妖魔是什么涩维? 我笑而不...
    開封第一講書人閱讀 56,780評論 1 285
  • 正文 為了忘掉前任,我火速辦了婚禮袁波,結(jié)果婚禮上瓦阐,老公的妹妹穿的比我還像新娘。我一直安慰自己篷牌,他們只是感情好睡蟋,可當我...
    茶點故事閱讀 65,890評論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著枷颊,像睡著了一般薄湿。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上偷卧,一...
    開封第一講書人閱讀 50,084評論 1 291
  • 那天豺瘤,我揣著相機與錄音,去河邊找鬼听诸。 笑死坐求,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的晌梨。 我是一名探鬼主播桥嗤,決...
    沈念sama閱讀 39,151評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼须妻,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了泛领?” 一聲冷哼從身側(cè)響起荒吏,我...
    開封第一講書人閱讀 37,912評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎渊鞋,沒想到半個月后绰更,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,355評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡锡宋,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,666評論 2 327
  • 正文 我和宋清朗相戀三年儡湾,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片执俩。...
    茶點故事閱讀 38,809評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡徐钠,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出役首,到底是詐尸還是另有隱情尝丐,我是刑警寧澤,帶...
    沈念sama閱讀 34,504評論 4 334
  • 正文 年R本政府宣布衡奥,位于F島的核電站爹袁,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏杰赛。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,150評論 3 317
  • 文/蒙蒙 一矮台、第九天 我趴在偏房一處隱蔽的房頂上張望乏屯。 院中可真熱鬧,春花似錦瘦赫、人聲如沸辰晕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽含友。三九已至,卻和暖如春校辩,著一層夾襖步出監(jiān)牢的瞬間窘问,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,121評論 1 267
  • 我被黑心中介騙來泰國打工宜咒, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留惠赫,地道東北人。 一個月前我還...
    沈念sama閱讀 46,628評論 2 362
  • 正文 我出身青樓故黑,卻偏偏與公主長得像儿咱,于是被迫代替她去往敵國和親庭砍。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,724評論 2 351

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