**版權(quán)聲明:本文為Carson_Ho原創(chuàng)文章,轉(zhuǎn)載請(qǐng)注明出處!
目錄

一、定義
使得某一元素在Android不同尺寸、不同分辨率的手機(jī)上具備相同的顯示效果
二、相關(guān)重要概念
屏幕尺寸
- 含義:手機(jī)對(duì)角線的物理尺寸
- 單位:英寸(inch),1英寸 = 2.54cm
Android手機(jī)常見的尺寸有5寸、5.5寸、6寸等等
屏幕分辨率
- 含義:手機(jī)橫向、縱向上的像素點(diǎn)數(shù)總和
一般描述成屏幕的"寬x高”=AxB
含義:屏幕在橫向方向(寬度)上有A個(gè)像素點(diǎn),在縱向方向
(高)有B個(gè)像素點(diǎn)
例子: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)系是:

假設(shè)一部手機(jī)的分辨率是1080x1920(px),屏幕大小是5寸,問密度是多少?
解:請(qǐng)直接套公式

- 含義:density-independent pixel,叫dp或dip,與終端上的實(shí)際物理像素點(diǎn)無(wú)關(guān)。
- 單位: dp,可以保證在不同屏幕像素密度的設(shè)備上顯示相同的效果
Android開發(fā)時(shí)用dp而不是px單位設(shè)置圖片大小,是Android特有的單位
場(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
Android開發(fā)時(shí)用此單位設(shè)置文字大小,可根據(jù)字體大小首選項(xiàng)進(jìn)行縮放,推薦使用12sp、14sp、18sp、22sp作為字體設(shè)置的大小,不推薦使用奇數(shù)和小數(shù),容易造成精度的丟失問題;小于12sp的字體會(huì)太小導(dǎo)致用戶看不清。
三、為什么要進(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ù)屏幕的配置來(lái)加載相應(yīng)的UI布局、用戶界面流程。 - 使得"圖片資源"匹配不同的屏幕密度
五、解決方案
- 問題:如何進(jìn)行屏幕尺寸匹配?
- 答:
布局匹配
本質(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ì)變化,與屏幕大小無(wú)關(guān),靈活性很強(qiáng) - LinearLayout
通過多層嵌套LinearLayout和組合使
用"wrap_content"和"match_parent"已經(jīng)可以構(gòu)建出足夠復(fù)雜的布局。但是LinearLayout無(wú)法準(zhǔn)確地控制子視圖之間的位置關(guān)系,只能簡(jiǎn)單的一個(gè)挨著一個(gè)地排列。
所以,對(duì)于屏幕適配來(lái)說,使用相對(duì)布局(RelativeLayout)將會(huì)是更好的解決方案
本質(zhì)2:根據(jù)屏幕的配置來(lái)加載相應(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
來(lái)完成上述設(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 為單位)來(lái)精確定位屏幕從而加載不同的UI資源
- 使用場(chǎng)景
你需要為標(biāo)準(zhǔn) 7 英寸平板電腦匹配雙面板布局(其最小寬度為 600 dp),在手機(jī)(較小的屏幕上)匹配單面板布局
解決方案:您可以使用上文中所述的單面板和雙面板這兩種布局,但您應(yīng)使用 sw600dp 指明雙面板布局僅適用于最小寬度為 600 dp 的屏幕,而不是使用 large 尺寸限定符。
- sw xxxdp,即small width的縮寫,其不區(qū)分方向,即無(wú)論是寬度還是高度,只要大于 xxxdp,就采用次此布局
- 例子:使用了layout-sw 600dp的最小寬度限定符,即無(wú)論是寬度還是高度,只要大于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ì)帶來(lái)一個(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ì)帶來(lái):文件名的重復(fù)從而帶來(lái)一些列后期維護(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>
- 2 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寸平板上:
版本低于 3.2 的平板會(huì)匹配 large的文件,. 版本高于 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 英寸平板電腦,橫向:雙面板,寬,帶操作欄
- 電視,橫向:雙面板,寬,帶操作欄
方法是:
- 先定義類別:單/雙面板、是否帶操作欄、寬/窄
定義在 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,通過獲取其值來(lái)動(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-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>
十、"布局組件"匹配
本質(zhì):使得布局組件自適應(yīng)屏幕尺寸
- 做法
使用"wrap_content"、"match_parent"和"weight“來(lái)控制視圖組件的寬度和高度
"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è)置寬度+剩余空間所占百分比寬幅
通過使用"wrap_content"、"match_parent"和"weight"來(lái)替代硬編碼的方式定義視圖大小&位置,你的視圖要么僅僅使用了需要的那邊一點(diǎn)空間,要么就會(huì)充滿所有可用的空間,即按需占據(jù)空間大小,能讓你的布局元素充分適應(yīng)你的屏幕尺寸
十一、“圖片資源”匹配
本質(zhì):使得圖片資源在不同屏幕密度上顯示相同的像素效果
- 做法:使用自動(dòng)拉伸位圖:Nine-Patch的圖片類型
假設(shè)需要匹配不同屏幕大小,你的圖片資源也必須自動(dòng)適應(yīng)各種屏幕尺寸
使用場(chǎng)景:一個(gè)按鈕的背景圖片必須能夠隨著按鈕大小的改變而改變。
使用普通的圖片將無(wú)法實(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è)來(lái)區(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ù)屏幕的配置來(lái)加載相應(yīng)的用戶界面流程
- 做法
進(jìn)行用戶界面流程的自適應(yīng)配置: - 1.確定當(dāng)前布局
- 2.根據(jù)當(dāng)前布局做出響應(yīng)
- 重復(fù)使用其他活動(dòng)中的片段
- 處理屏幕配置變化
步驟1:確定當(dāng)前布局
由于每種布局的實(shí)施都會(huì)稍有不同,因此我們需要先確定當(dāng)前向用戶顯示的布局。例如,我們可以先了解用戶所處的是“單面板”模式還是“雙面板”模式。要做到這一點(diǎn),可以通過查詢指定視圖是否存在以及是否已顯示出來(lái)。
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了。
