標籤:android 螢幕適配 尺寸
Android的螢幕類型有幾百種不同的尺寸,從小型的手機到大型的電視機。因此要使我們的應用程式相容不同螢幕尺寸,同一個應用就可以提供給更多的使用者使用。
一、支援不同的螢幕尺寸
1、使用“wrap_content"和”match_parent"
為了確保布局的靈活性,來適應不同尺寸的螢幕,我們應該使用“wrap_content"來匹配組件的最小尺寸和使用”match_parent"來設定某些視圖來匹配父視圖的大小。這樣設定和直接設定視圖大小(如48dip)不同的是該視圖的空間可以隨著螢幕尺寸(父視圖的大小)隨意擴充。例如如下布局:
<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>
當我們翻轉手機螢幕可以看到橫向和豎向的螢幕適配如下:
2、使用Relative_layout
我們可以使用LinearLayout通過“wrap_content"和”match_parent"來實現很多複雜的布局,但是LinearLayout擅長控制的是線性關係,如果是要精確控制平面關係,使用Relative_layout比較合適,它可以指定兩個組件之間的空間關係。例如下面代碼:
<?xml的version = "1.0" encoding = "utf-8" ?> <RelativeLayout xmlns:android = "http://schemas.android.com/apk/res/android" android:layout_width = "match_parent" android:layout_height = "match_parent" > <TextView android:id = "@+id/label" android:layout_width = "match_parent" android:layout_height = "wrap_content" android:text = "Type here:" /> <EditText android:id = "@+id/entry" android:layout_width = "match_parent" android:layout_height = "wrap_content" android:layout_below = "@id/label" /> <Button android:id = "@+id/ok" android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:layout_below = "@id/entry" android:layout_alignParentRight = "true" android:layout_marginLeft = "10dp" android:text = "OK" /> <Button android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:layout_toLeftOf = "@id/ok" android:layout_alignTop = "@id/ok" android:text = "Cancel" /> </RelativeLayout>
在小螢幕尺寸的QVGA手機上顯示如下:
在大螢幕的WSVGA螢幕上顯示如下:
3、使用尺寸限定符
上面我們通過“wrap_content"、”match_parent"、“relative_layout"的方法來實現不同螢幕尺寸的視圖伸展,有效解決了螢幕尺寸問題,除了這些方法外我們還可以使用尺寸限定符來針對不同的螢幕來做特殊的介面布局。
第一列是螢幕的特徵,有尺寸、密度、方向、長寬比
第二列是限定符的寫法(如large,我們就需要建立一個檔案夾名稱為layout-large)
第三列是相關解釋和描述
例如我們現在在我們的res下建立兩個檔案夾通過不同的限定符檔案夾名稱來匹配不同尺寸的螢幕
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>
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>
上面布局中在大螢幕中我們將兩個大視圖放到了整個螢幕,二小螢幕中我們只放置了一個視圖。我們的裝置會根據螢幕尺寸來自動尋找自己的布局。
4、使用最小寬度限定符
上面根據螢幕尺寸來匹配不同的布局檔案,但是很多時候我們可能在不同的大屏手機中需要分別顯示不同的布局(例如Galaxy Tab顯示5個還是7個),在Android3.2以後就有了最小寬度限定符來解決這個問題。
假設sw600dp來表示我們的最小寬度,則布局檔案就可以有如下表示:
小螢幕手機適配的布局 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>
裝置寬度大於或等於600dp的布局 res/layout/layout-sw600dp.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>
要注意的是這種限定符在3.2以前的版本手機上是不支援的。在3.2之前還必須用尺寸限定符large來代替。
5、使用layout別名
綜合上面的分析,如果我們要支援一個包含大螢幕尺寸的裝置必須包含例如下面幾個布局來匹配
res/layout/main.xml
res/layout/layout-large
res/layout/layout-sw600dp
最後這兩個檔案的作用是相同的,是為了支援3.2以下和以上版本,為了避免混淆和維護難度,我們可以給這些布局起別名,比如下面的布局名:
res/layout/main.xml 單面板布局
res/layout/main_twopanes.xml 雙面板布局
並添加這兩個檔案
res/values-large/layout.xml
<resources> <item name="main" type="layout">@layout/main_twopanes</item></resources>
res/values-sw600dp/layout.xml
<resources> <item name="main" type="layout">@layout/main_twopanes</item></resources>
可以看到這兩個檔案的內容相同,他們只是建立起一個main和mian_twospanes的聯絡,可以通過螢幕尺寸來分別擷取不同的value檔案下所對應的布局檔案別名。
6、使用方向限定符
有的時候我們的應用可能需要翻轉手機能獲得更好的效果,此時的布局也需要做相應的改變,也可以分別做出對應的布局檔案。請參照上面的表格(land 和 port)。
7、使用Nine-Patch圖
對於不同的螢幕尺寸通常我們需要使用不同尺寸的圖片資源,所以在設計可變大小的組件時,一定要使用Nine-Patch圖。
如的Nine-Patch圖在不同尺寸手機上的展開效果如下:
有關Nine-Patch的製作方法請參考我的另一篇博文:http://blog.csdn.net/dawanganban/article/details/17379193
二、支援不同的螢幕密度
我們在設計布局的時候不能使用絕對的像素尺寸,而應該使用dp和sp.不同裝置具有不同的螢幕密度,1英寸的不同密度手機上的像素個數是不同的。為了讓大家搞清楚這些基本概念,我逐一解釋一下:
dpi 像素密度:像素密度,即每英寸螢幕所擁有的像素數,像素密度越大,顯示畫面細節就越豐富。
我們可以用這個公式表示 1dpi = 1pix / 1in
dp (dip)裝置獨立像素:在螢幕密度為160的顯示屏上,1dip=1px
有了這些概念,我們來算一下,1dip是多長(是多少英寸)
result = in / dip
result = in / px (根據dp的定義)
result = 1 / (px / in)
result = 1 / dpi
result = 1 / 160
從上面的推導可以看出在螢幕密度為160的顯示屏上 1dip其實就是 1 / 160 英寸,是一個螢幕尺寸上的絕對單位。
Android中為我們提供了適配不同解析度的資源套件,我們只需要做一套資源就可以自動幫我們換算成相應dpi(解析度)下的尺寸,放大及縮小比例如所示。
三、不同UI的代碼邏輯適配
1、確定當前布局
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 ; } }如上面代碼,我們可以通過某些View的可見度來判斷選用的布局檔案。
2、根據不同的布局,做出不同的邏輯
@Overridepublic 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、使用程式碼片段實現重用
<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>
設計相容不同的螢幕尺寸的Android介面