android 不同大小的屏幕專題及常見問題 - CSDN

2021-01-07 CSDN技術社區

轉載請註明出處:http://blog.csdn.net/guolin_blog/article/details/8830286

原文地址為:http://developer.android.com/training/multiscreen/screensizes.html


本文將告訴你如何讓你的應用程式支持各種不同屏幕大小,主要通過以下幾種辦法:

讓你的布局能充分的自適應屏幕根據屏幕的配置來加載合適的UI布局確保正確的布局應用在正確的設備屏幕上提供可以根據屏幕大小自動伸縮的圖片
使用 "wrap_content" 和 "match_parent"


 為了確保你的布局能夠自適應各種不同屏幕大小,你應該在布局的視圖中使用"wrap_content""match_parent"來確定它的寬和高。如果你使用了"wrap_content",相應視圖的寬和高就會被設定成剛好能夠包含視圖中內容的最小值。而如果你使用了"match_parent"(在Android API 8之前叫作"fill_parent"),就會讓視圖的寬和高延伸至充滿整個父布局。


通過使用"wrap_content""match_parent"來替代硬編碼的方式定義視圖大小,你的視圖要麼僅僅使用了需要的那邊一點空間,要麼就會充滿所有可用的空間。例如:

<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>

注意上面的例子中是如何使用

"wrap_content"

"match_parent"

來給控制項定義寬高的,這讓整個布局可以正確地適應不同屏幕的大小,甚至是橫屏。


下圖是這個布局分別在豎屏和橫屏時顯示的結果,注意控制項的寬和高是根據屏幕自適應的。




使用RelativeLayout


通過多層嵌套LinearLayout和組合使用"wrap_content""match_parent"已經可以構建出足夠複雜的布局。但是LinearLayout無法允許你準確地控制子視圖之前的位置關係,所有LinearLayout中的子視圖只能簡單的一個挨著一個地排列。如果你需要讓子視圖能夠有更多的排列方式,而不是簡單地排成一行或一列,使用RelativeLayout將會是更好的解決方案。RelativeLayout允許布局的子控制項之間使用相對定位的方式控制控制項的位置,比如你可以讓一個子視圖居屏幕左側對齊,讓另一個子視圖居屏幕右側對齊。


例如:

<?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屏幕上顯示的結果。




下圖展示了這個布局在一個更大的屏幕上顯示的結果。




可以注意到,即使屏幕的大小改變,視圖之前的相對位置都沒有改變。


使用Size限定符


雖然使用以上幾種方式可以解決屏幕適配性的問題,但是那些通過伸縮控制項來適應各種不同屏幕大小的布局,未必就是提供了最好的用戶體驗。你的應用程式應該不僅僅實現了可自適應的布局,還應該提供一些方案根據屏幕的配置來加載不同的布局,可以通過配置限定符(configuration qualifiers)來實現。配置限定符允許程序在運行時根據當前設備的配置自動加載合適的資源(比如為不同尺寸屏幕設計不同的布局)。


現在有很多的應用程式為了支持大屏設備,都會實現「two pane」模式(程序會在左側的面板上展示一個包含子項的List,在右側面板上展示內容)。平板和電視設備的屏幕都很大,足夠同時顯示兩個面板,而手機屏幕一次只能顯示一個面板,兩個面板需要分開顯示。所以,為了實現這種布局,你可能需要以下文件:


res/layout/main.xml,single-pane(默認)布局:

<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

,two-pane布局:

<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>

請注意第二個布局的目錄名中包含了large限定符,那些被定義為大屏的設備(比如7寸以上的平板)會自動加載此布局,而小屏設備會加載另一個默認的布局。


使用Smallest-width限定符


使用Size限定符有一個問題會讓很多程式設計師感到頭疼,large到底是指多大呢?很多應用程式都希望能夠更自由地為不同屏幕設備加載不同的布局,不管它們是不是被系統認定為"large"。這就是Android為什麼在3.2以後引入了"Smallest-width"限定符。


Smallest-width限定符允許你設定一個具體的最小值(以dp為單位)來指定屏幕。例如,7寸的平板最小寬度是600dp,所以如果你想讓你的UI在這種屏幕上顯示two pane,在更小的屏幕上顯示single pane,你可以使用sw600dp來表示你想在600dp以上寬度的屏幕上使用two pane模式。


res/layout/main.xml,single-pane(默認)布局:

<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-sw600dp/main.xml

,two-pane布局:

<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>

這意味著,那些最小屏幕寬度大於600dp的設備會選擇

layout-sw600dp/main.xml

(two-pane)布局,而更小屏幕的設備將會選擇

layout/main.xml

(single-pane)布局。


然而,使用早於Android 3.2系統的設備將無法識別sw600dp這個限定符,所以你還是同時需要使用large限定符。這樣你就需要在res/layout-large和res/layout-sw600dp目錄下都添加一個相同的main.xml。下節你將會看到如何避免重複定義這種布局的技巧。


使用布局別名


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

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


最後的兩個文件是完全相同的,為了要解決這種重複,你需要使用別名技巧。例如,你可以定義以下布局:

res/layout/main.xml, single-pane布局res/layout/main_twopanes.xml, two-pane布局


加入以下兩個文件:

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定義了一個別名main_twopanes。這樣兩個layout.xml都只是引用了@layout/main_twopanes,就避免了重複定義布局文件的情況。


使用Orientation限定符


 有些布局會在橫屏和豎屏的情況下都顯示的很好,但是多數情況下這些布局都可以再調整的。在News Reader示例程序中,布局在不同屏幕尺寸和不同屏幕方向中是這樣顯示的:

小屏幕, 豎屏: 單面板, 顯示logo小屏幕, 橫屏: 單面板, 顯示logo7寸平板, 豎屏: 單面板, 顯示action bar7寸平板, 橫屏: 雙面板, 寬, 顯示action bar10寸平板, 豎屏: 雙面板, 窄, 顯示action bar10寸平板, 橫屏: 雙面板, 寬, 顯示action bar電視, 橫屏: 雙面板, 寬, 顯示action bar


所有這些布局都是定義在 res/layout/ 這個目錄下,為了要讓設備根據屏幕配置來加載正確的布局,程序需要使用布局別名來實現。

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>

現在所有需要的布局都已經定義好了,剩下的只要使用限定符來讓各個設備根據屏幕配置加載正確的布局了。你現在就可以使用布局別名技術:

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>

res/values-large-land/layouts.xml:

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

res/values-large-port/layouts.xml:

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


使用Nine-Patch圖片


支持不同屏幕大小通常情況下也意味著,你的圖片資源也需要有自適應的能力。例如,一個按鈕的背景圖片必須能夠隨著按鈕大小的改變而改變。


如果你想使用普通的圖片來實現上述功能,你很快就會發現結果是令人失望的,因為運行時會均勻地拉伸或壓縮你的圖片。解決方案是使用nine-patch圖片,它是一種被特殊處理過的PNG圖片,你可以指定哪些區域可以拉伸而哪些區域不可以。


因而,當你設計需要在不同大小的控制項中使用的圖片時,最好的方法就是用nine-patch圖片。為了將圖片轉換成nine-patch圖片,你可以從一張普通的圖片開始:




然後通過SDK中帶有的draw9patch工具打開這張圖片(工具位置在SDK的tools目錄下),你可以在圖片的左邊框和上邊框繪製來標記哪些區域可以被拉伸。你也可以在圖片的右邊框和下邊框繪製來標記內容需要放置在哪個區域。結果如下圖所示:




注意圖片邊框上的黑色像素,在上邊框和左邊框的部分表示當圖片需要拉伸時就拉伸黑點標記的位置。在下邊框和右邊框的部分表示內容將會被放置的區域。


同時需要注意,這張圖片的後綴名是 .9.png。你必須要使用這個後綴名,因為系統就是根據這個來區別nine-patch圖片和普通的PNG圖片的。


當你需要在一個控制項中使用nine-patch圖片時(如android:background="@drawable/button"),系統就會根據控制項的大小自動地拉伸你想要拉伸的部分,效果如下圖所示:




關注我的技術公眾號,每天都有優質技術文章推送。關注我的娛樂公眾號,工作、學習累了的時候放鬆一下自己。

微信掃一掃下方二維碼即可關注:

        

相關焦點

  • android 自定義view大小專題及常見問題 - CSDN
    ScrollView嵌套ListView問題?layout系統為什麼要有layout過程?layout過程都幹了點什麼事?draw系統為什麼要有draw過程?draw過程都幹了點什麼事?(這個模式主要用於系統內部多次Measure的情形,並不是真的說你想要多大最後就真有多大)EXACTLY父控制項已經知道你所需的精確大小,你的最終大小應該就是這麼大。AT_MOST你的大小不能大於父控制項給你指定的size,但具體是多少,得看你自己的實現。
  • android布局詳解專題及常見問題 - CSDN
    <include android:id=」@+id/cell3 layout=」@layout/workspace_screen」 /></LinearLayout>  上面的代碼中的<include>標籤還使用了一個android:id屬性,實際上,該屬性指定的是workspace_screen.xml布局文件中的根節點的android
  • android tv放大專題及常見問題 - CSDN
    我這button離父view左邊是0上邊也是0也就是y軸的高度也是0,而這列印出來是228,就說明這個是相對於屏幕的,屏幕就有狀態欄和標題欄,獲取狀態欄高度Rect frame = new Rect;import android.os.Bundle;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.view.WindowManager;import android.widget.BaseAdapter;import android.widget.ImageView
  • android啟動頁設計專題及常見問題 - CSDN
    轉載請註明出處:http://blog.csdn.net/wangjihuanghun/article/details/63255144啟動頁幾乎成為了每個app的標配,有些商家在啟動頁中增加了開屏廣告以此帶來更多的收入。
  • android 復用 布局優化專題及常見問題 - CSDN
    1、布局重用<include /> <include />標籤能夠重用布局文件,簡單的使用如下:     <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"           android:orientation
  • android 從後臺啟動頁面專題及常見問題 - CSDN
    layout.xml首先創建此頁面的布局文件:<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent">
  • android 進度條顯示時間專題及常見問題 - CSDN
    定義一個attrs.xml自定義CircleProgressViewpackage com.sample.circleprogressview.widget;import android.animation.ValueAnimator;import android.content.Context
  • android 自定義view大小 - CSDN
    直觀來說,可能有以下問題需要考慮:自定的View最好不要超過父控制項的大小,這樣才能保證自己能在父控制項中完整顯示自定的View(如果是ViewGroup)的子控制項最好不要超過自己的大小,這樣才能保證子控制項顯示完整如果明確為View指定了尺寸,最好按照指定的尺寸設置以上三個問題可能是自定義ViewGroup最需要考慮的問題
  • android通過代碼實現的多布局專題及常見問題 - CSDN
    但是這樣就遇到了很多問題。 首先是SeekBar設置setProgressDrawable問題。因為我們的是視頻播放器,所以這個SeekBar需要有背景、緩衝進度和播放進度,最好的方法就是用layer-list 的xml布局實現,類似這樣:<?xml version="1.0" encoding="utf-8"?
  • android app被殺原因專題及常見問題 - CSDN
    分析長按HOME鍵清理App最終會執行到ActivityManagerService.cleanUpRemovedTaskLocked方法中,ActivityManagerService類在文件"frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java"中,
  • android 首次打開判斷專題及常見問題 - CSDN
    前言用真機運行appium代碼,首次打開app有的手機會出現權限彈窗問題,一般這種彈窗都是在引導頁前面或者引導頁後面出現。權限彈窗上面的按鈕都是固定的,只需要定位到「始終允許」按鈕,點擊確定就可以了。還有一個問題是這種彈窗的個數不確定,有的app是2個有的是3個,為了解決這個問題,可以專門寫個判斷方法。
  • bootstrap 寬度 自適應布局專題及常見問題 - CSDN
    一共5種: [1]float [2]inline-block [3]table [4]absolute [5]flex- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -思路一: float說起兩列布局,最常見的就是使用
  • android藍牙框架專題及常見問題 - CSDN
    代碼來源於Android P,本文相關代碼:client:frameworks/base/core/java/android/bluetooth/*system/bt/binder/android/bluetooth/**.aidlservie:framework/base/services/core/java/com/android/server
  • android 服務啟動後專題及常見問題 - CSDN
    (ActivityManagerService.this) { mDidUpdate = true; } showBootMessage(mContext.getText( R.string.android_upgrading_complete
  • android中實例化類專題及常見問題 - CSDN
    轉自:http://www.android123.com.cn/androidkaifa/687.html三、在JNI中構造和實例化Java類 public class AndroidJniDemo4{ public static native
  • android藍牙相關框架專題及常見問題 - CSDN
    代碼來源於Android P,本文相關代碼:client:frameworks/base/core/java/android/bluetooth/*system/bt/binder/android/bluetooth/**.aidlservie:framework/base/services/core/java/com/android/server/BluetoothService.java
  • android audio 焦點專題及常見問題 - CSDN
    我們android系統裡面會安裝各種多媒體軟體,如果不制定一個有效合理的規則,各個應用各自為政,那麼可能就會出現各種播放器、軟體的混音。音頻焦點機制規定某一時刻只能有一個應用獲取到聲音的焦點,這個時候就可以發出聲音。當然,在這個應用獲取到焦點之前,需要通知其他所用的應用失去焦點。
  • androidaudio焦點專題及常見問題 - CSDN
    我們android系統裡面會安裝各種多媒體軟體,如果不制定一個有效合理的規則,各個應用各自為政,那麼可能就會出現各種播放器、軟體的混音。音頻焦點機制規定某一時刻只能有一個應用獲取到聲音的焦點,這個時候就可以發出聲音。當然,在這個應用獲取到焦點之前,需要通知其他所用的應用失去焦點。
  • android 前攝像頭對焦專題及常見問題 - CSDN
    * * Rotate, scale and translate touch rectangle using matrix configured in* {@link SurfaceHolder.Callback#surfaceChanged(android.view.SurfaceHolder, int, int, int)}*/
  • android 排列 - CSDN
    一、LinearLayout線性布局,這個東西,從外框上可以理解為一個div,他首先是一個一個從上往下羅列在屏幕上。每一個LinearLayout裡面又可分為垂直布局(android:orientation="vertical")和水平布局(android:orientation="horizontal" )。