第一部分:開發前的准備-第四章 多分辨率多屏幕的支持


第4章 多屏幕多分辨率的支持

如果你買過Android手機的話,銷售員一般會向你推薦這個android手機是最新版的系統啦,屏幕有多大,分辨率是多少之類的。這只是外表上的多屏幕和多分辨率,其實android內在還有一些影響因素,例如“密度”的概念。本章為詳細的為你解釋一些基礎概念並適當的舉一些例子教你怎么處理關於多屏幕多分辨率的支持。 雖然Android系統內置有一些機制能使用多屏幕多分辨率,但我們還是應該在加點外力來更加優化用戶體驗的效果。

4.1多屏幕支持概述

4.1.1基本術語和概念

屏幕大小

根據屏幕對角線實際測量的物理大小(android已經根據屏幕大小分為四類small, normal, large, extra large)

屏幕密度

屏幕物理區域一個單位(一般用英寸)的像素數量,一般簡稱dpi(‘dots per inch’每英寸中包含的點的數量,記住DPI這個概念很重要)

這里android也分為四類 low, medium, high, extra high.

方向

從用戶的角度看設備只有兩個方向,那就是橫屏和豎屏。關於橫豎屏最好也要出一套相對應的UI,因為長寬比不一樣,特別是對於軟件項目一般都是出兩套(游戲一般都會鎖定一個方向)。

分辨率

一個物理屏幕上像素點的總數。一般我們的應用不會直接使用分辨率,而是使用密度和屏幕大小(但某些特殊情況下,可以指定分辨率)

獨立密度像素(Density-independent pixel ‘dip’)

一個虛擬的單位,用來定義UI布局的。它是表述布局的尺寸大小或者位置。

dip(注 意dip是獨立像素單位,dpi是屏幕密度)等價於一個160dpi(medium密度)的屏幕,運行時系統會根據你實際屏幕的密度來自動處理縮放。像素和dip 的轉換公式為px =dp*(dpi/160) 。例如在240密度的屏幕上一個dp等於1.5個像素(dp=px*1.5)。以后我們應該盡量使用dip單位布局,不要使用像素單位。這樣會使你的應用屏幕兼容性更好。最后我們應該區分dpi和dip它們一個字母的不同代表的意思就不一樣。以后程序中我們一般使用dp來代替dip用來描述位置和尺寸大小,而dpi則是屏幕密度,這里大家需要稍微留心一下。下面我們來舉個游戲的例子:

關於android多屏幕多分辨率這道門檻,我們可以把它看成一個boss,要戰勝這個boss我們需要了解它的5個弱點(也可以理解成游戲套路)

  1. 屏幕大小---boss的體型,boss都有體型之分的,例如WOW中的BOSS大部分都是巨型,而有些游戲中的boss比較小,例如劍網3的boss就比較小。
  2. 屏幕密度---boss的模型細粒度,有些boss你能看清它的每個外觀細節,但有些boss就比較模糊,雖然你的電腦顯卡或者游戲模型的材質會影響外觀細節。但請忽略它們!
  3. 方向---這個要以我們的角度來觀察boss才能得出結論,例如你靠近boss並站在高處和你遠離boss站在低處看boss完全是兩個感覺。
  4. 分辨率---這個可以理解為對boss總體的外觀和風格,它是由boss的體型和boss的模型細粒度加在一起體現出的一種外觀和風格,所以說分辨率我們一般是通過密度和屏幕大小來匹配。
  5. dip---boss的傷害公式,boss的傷害其實是一個數字,但這個數字是有公式轉換的,例如法系攻擊,物理攻擊的都是有一個公式轉換后在附加到我們身上。當然請不要糾結你的防御,抗性之類的,dip就是一種轉換公式,讓不同的boss都能統一轉換成正確的傷害。

4.1.2多屏幕支持的范圍

Android1.6開始就支持多屏幕和密度了,這都是為了更好的用戶體驗,為了簡化我們多屏幕的開發。android提供了一組范圍讓我們使用:

關於屏幕大小: small, normal, large, xlarge(看來目前游戲boss的體型就這四種)

注意: android3.2會有些不同,以后我們在講平板和手機支持時會說明

屏幕密度: ldpi (low), mdpi (medium), hdpi (high), xhdpi (extra high) (boss的模型細粒度目前也就四種了)。這些廣義的大小和密度都是基於normal大小和mdpi來當做標准的。一般來說我們分辨率為800*480或者854*480的手機密度都是240(hdpi),屏幕大小都為large。

每一個大小和密度都有一個跨越幅度。但這些幅度中具體的微調我們是不用關心的,android會幫我們處理,下面我們來看圖 4-1:

 

 圖4-1 實際大小和實際密度的取值范圍(這是個近似值)

 

我們設計UI都會要考慮一個最小化的空間,android中都是使用dp(dip)單位的。以下是官方參考

xlarge 屏幕至少960dp x 720dp

large 屏幕至少 640dp x 480dp

normal 屏幕至少 470dp x 320dp

small 屏幕至少 426dp x 320dp

屏幕大小和密度是可以獨立的,不是說一個5寸屏的密度就一定是hdpi。有一個很重要的例子就是例如一個WVGA (800×480)屏幕可能在不同的設備上會有mdpi和hdpid兩種密度。也就是說同樣體型的boss,有的模型很粗糙,有的很細膩。

 

4.1.3獨立密度

獨立密度是很重要的,因為沒有它,一個UI元素(比如一個按鈕)會出現在一個物理屏幕很大,但密度很少的顯示效果(看起來就是像是被強行放大的,失真很嚴重)。這樣相對位置的改變會出問題,下面我們來看圖:

 

 圖4-2 你的應用沒有支持不同密度產生的效果

 

圖4-3你的應用具有良好的支持而產生的效果

android 系統幫助你的應用實現獨立密度的方法有兩種:

1.系統縮放dp單位來適用當前屏幕密度

2.系統基於當前屏幕密度縮放drawable資源到適用的大小

圖 4-2是用像素單位來定義的大小。你發現他們的布局完全變了,有的大有的小。這是因為他們的實際屏幕大小可能是一樣的,高密度屏幕每英寸的像素更多(所以你會發現像素一樣,但高密度的設備顯示出來的效果卻很小)。圖4-2使用的是dp單位,基於mdpi密度的設備它不會變化,ldpi它會自動縮小,hdpi它會自動放大。所以效果非常好。圖片顯示出來的樣子和大小完全一樣。

使用密度系統會縮放圖片使之看上去完全一樣,但細心的你會發現有些圖片變模糊了。所以我們應該提供可選擇的圖片資源讓系統來自動選擇圖片以適應不同的密度。所以用Eclipse自動生成的工程項目中的hdpi,mdpi,ldpi三個文件夾就是用在這里的。這樣就不會有模糊的感覺了。當然對於矢量圖來說放大的失真也沒什么影響,這里可以理解為只針對位圖。

4.2怎樣支持多屏幕

以上我們學習了這么多的理論基礎。現在我們應該優雅的處理它們了。

1. 明確的在manifest文件中指出你的應用支持的屏幕大小。

我們可以有選擇性的過濾掉一些老掉牙的設備,以減輕我們的工作量。但這並不是一個好的方法僅供參考。在manifest 中使用節點<supports-screens>

2. 根據不同的屏幕大小提供不同的布局

默認的android會調整你應用的布局來適應當前設備的屏幕。大多數情況下可以滿足,但某些特殊情況,你的UI可能需要一個更精確的調整。例如,一個larger 屏幕,你可能想要利用額外的屏幕空間調整位置和一些元素的大小,或者一個小屏幕中,你可能需要調整到剛好合適。比如你需要適應一個extra large 屏幕。你可以在文件夾layout-xlarge/下放置布局(讀者請記住一般layut下放的都是xml布局文件)。

Android 3.2開始,有一種新的方式。例如你的平板需求至少600dp的屏幕寬度,你可以使用layout-sw600dp 這種文件夾放置你的布局文件。以后我們在平板一節會詳細描述。

3. 根據不同的屏幕密度提供不同的位圖

默認android會縮放你的位圖(.png.jpg.gif),另外還有一種專用的Nine-Patch(.9.png)。例如,你的應用提供的位圖僅僅為標准密度(mdpi),那么在hdpi的屏幕上這些位置會被等比放大。所以我們應該有選擇性的對於不同的屏幕密度包含不同的分辨率。

所以android針對圖片資源配置后綴,前面我們知道的4種密度(ldpi,mdpi,hdpi,xhpi),如果用於高密度的屏幕,我們應該使用drawable- hdpi/這種文件夾。以上關於屏幕大小和密度的后綴都符合屏幕支持的那些范圍。

在運行時, 對於給定的資源系統會使用以下這些步驟來顯示:

1. 系統會使用合適的替代資源

基於當前屏幕的大小和密度,系統會針對屏幕的密度和大小使用資源。例如,如果設備有一個 hdpi的屏幕那么當App請求一個drawable 資源時,系統會在最匹配的的設備配置下的drawable 資源目錄尋找。可以取決於其他可替代的資源,使用drawable-hdpi/的資源目錄最匹配的,所以系統會使用drawable-hdpi目錄下的資源。

2. 如果沒有可用的匹配資源,系統會使用默認資源等比放大或縮小以匹配當前屏幕的大小和密度。

這里的默認資源是沒有后綴的。例如,“drawable”就是默認的drawable/ 資源。系統會認為默認的資源都是基於normal 屏幕大小和medium 密度設計的。系統會等比縮放默認的密度資源來匹配hdpi密度或者ldpi密度。當系統沒有找到針對密度資源的目錄時,它就一直會使用默認的資源。例如,如果系統想找一個ldpi(低密度)的資源,但找不到。那么系統會等比縮小hdpi的資源,為什么不尋找mdpi呢?因為系統對於hdpi更容易縮放,它的系數為0.5,相比mdpi的0.75來說。0.5的的性價比更高(方便計算,正確率也高一點)。關於這一點最好的證明就是android版本的QQ瀏覽器。你解壓后發現它關於drawable就只有drawable和drawable-hdpi兩個文件夾,看來騰訊里android的開發者應該很熟悉android系統規律了,因為默認的drawable 就是mdpi,只需要定義一套hdpi的drawable資源就行了。

4.2.1使用配置后綴

Android支持幾種配置后綴,它允許你控制系統有選擇性的篩選基於當前屏幕設備的資源文件。一個配置后綴就是一個String你可以在資源目錄文件夾下追加指定的后綴即可。使用一個配置后綴的方法步驟:

1.在你的工程res/目錄下創建一個新的目錄,格式為<資源名>-<后綴>: 

<資源名>是標准的資源名字(例如 drawable或者layout)

<后綴> 是指定屏幕配置使用哪一種資源(例如hdpi或者xlarge)

我們可以使用的后綴不僅僅只有一個哦,在一個文件夾下我們可以同時使用多種后綴來限定資源,使用"-"即可。

2.在新的目錄中保存合適資源,資源文件的命名必須和默認資源文件一樣。

例如 xlarge是一個后綴用於extra large 屏幕。當你追加后綴時(例如layout-xlarge) ,它說明系統會在extra large屏幕上使用這些資源

屏幕特征

后綴

描述

大小

small

資源用於small大小的屏幕.

normal

資源用於normal 大小的屏幕。(這是默認的基准大小)

large

資源用於large 大小的屏幕

xlarge

資源用於extra large 大小的屏幕

密度

ldpi

資源用於 low-density (ldpi) 密度的屏幕 (~120dpi).

mdpi

資源用於medium-density (mdpi) 密度的屏幕 (~160dpi).

(這是默認的基准密度.)

hdpi

資源用於high-density (hdpi) 密度的屏幕 (~240dpi).

xhdpi

資源用於extra high-density (xhdpi) 密度的屏幕 (~320dpi).

nodpi

資源用於所有密度. 系統不會根據當前屏幕密度去縮放資源

tvdpi

資源用於mdpi 和hdpi兩者之間的某的密度;大約是213dpi。

這個很少用到。它主要用於電視,大多數App不需要用到它。

如果你需要tvdpi資源,它的大小大概是1.33*mdpi(160)例如,

一個在mdpi下100px*100px的圖片,那么在 tvdpi中它會

變成133px*133px。的圖片,那么在 tvdpi中它會變成133px*133px。

方向

land

資源用於橫屏

port

資源用於豎屏

長寬比

long

資源用於長寬比相差很遠的配置(相對於4寸(normal)屏幕左右基准屏幕)

notlong

資源用於長寬比差不多的配置(相對論,同上)

表格4-1 后綴配置表

注意: 如果對於android3.2或者更高的版本,有一些新的后綴,等下我們會講解

下面我們就來舉一些詳細的例子:

res/layout/my_layout.xml             // 用於normal 屏幕大小的布局 ("默認")
res/layout-small/my_layout.xml       // 用於small 屏幕大小的布局
res/layout-large/my_layout.xml       // 用於large屏幕大小的布局
res/layout-xlarge/my_layout.xml      // 用於extra large屏幕大小的布局
res/layout-xlarge-land/my_layout.xml // 於extra large屏幕大小並且是橫屏的布局

res/drawable-mdpi/my_icon.png        // 用於中等密度的位圖
res/drawable-hdpi/my_icon.png        // 用於高密度的位圖
res/drawable-xhdpi/my_icon.png       // 用於超高密度的位圖

當android系統在運行時選擇資源時,當你沒有加后綴時它自己有一定的邏輯判斷來匹配最適合的資源。當基於使用大小的后綴時,如果當前沒有資源更好的匹配你的后綴,那么系統會使用比當前屏幕更小的資源來計算(例如,如果你沒有添加large后綴,那么一個large大小的屏幕將會使用在normal(默認的)大小的屏幕資源來放大后顯示),如果可用的資源后綴比當前屏幕更大(其實還是沒匹配上),那么系統將不使用它們(例如你吧所有layout資源放入xlarge后綴中,但設備是一個normal屏幕,系統就不會使用這些資源)。

是不是有點頭暈了,簡要的概述下就是如果沒有匹配的系統會使用默認的資源,如果連默認下都沒有放資源並且沒有匹配到你的后綴,那么系統就沒有資源可用啦。

注意:某些情況下你可能需要用到nodpi后綴,因為你可能不想要它被縮放,或者你想要在運行時通過代碼手動縮放它。 

4.2.2設計可供選擇的Layouts和drawables

我們應該根據於自己應用程序的需求來創建可供選擇的資源類型。通常,你應該使用大小和方向后綴來提供可選擇的Layout資源,使用密度后綴來提供可選擇的位圖drawable資源

可供選擇的layouts

你應該知道你的應用是否有這個需求,是否需要根據不同的屏幕來提供可選擇的布局。例如:

1.當在一個small屏幕上測試時,你發現你的布局沒有完全符合你的要求或者是沒有匹配好屏幕。例如一排按鈕沒有很好的在small屏幕上顯示。這種情況你應該為small屏幕提供一個可供選擇的布局用來調整按鈕的大小或者位置。

2.當在一個extra large屏幕測試時, 如果沒有有效利用大屏幕或者明顯的被拉伸了,這種情況你也應該提供一種根據extra large屏幕的布局,並且最好再優化它以適應將來的平板設備

雖然你的App沒有提供大屏幕的布局運行起來也沒問題,但UI被明顯拉伸的感覺會讓用戶覺得這個應用不太精致,用戶體驗會大打折扣

3.當在橫屏和豎屏對比測試時, 你應該注意到UI元素在豎屏下是在底部,橫屏下卻是右邊。如果你一直需要都在底部的話,你也應該配置后綴

總的來說,你應該確保你的應用布局如下:

(1)適用於小屏幕

(2)優化應用程序使之在大屏幕上利用額外的空間

(3)優化橫豎屏

如果你的UI使用位圖,那么你應該使用nine-patch 位圖文件。nine-patch 這是android提供的一種格式並且它還提供一種根據讓你吧美工出的圖片稍微修飾。這種格式能允許你設置可以縮放的2D范圍。當系統需要縮放時,系統會在你指定區域縮放 Nine-Patch位圖。這樣在不同的屏幕大小下你就不需要提供不同的位圖資源了(可以節省APK的大小)。因為Nine-Patch會自動調整它的。但在不同的屏幕密度下你應該還是提供可供選擇的Nine-Patch 文件。這樣你的應用才會更健壯。關於nine-patch的使用我們以后會在第二大篇的圖形章詳細講述。

可供選擇的drawables

幾乎每一個應用都會根據不同的密度提供可選擇的drawable資源,因為這對於用戶體驗和UI真的很重要。下面我們來看一下圖4-4的密度轉換圖

 

圖4-4 根據每一個密度下drawable下位圖的相對大小(目前4種技能應該夠用了)

注意: 根據密度你僅需要提供drawable下的位圖文件,如果你使用Xml來定義shape,colors或者其他drawable的資源,你就應該放到"drawable/"默認目錄下

根據不同的密度提供可選擇的位圖drawable資源時,你應該在四種密度下使用3:4:6:8的縮放比。讀者可以參考工程下每個不同的drawable里的icon尺寸:

36x36 ldpi

48x48 mdpi

72x72 hdpi

96x96 xhdpi

 

4.3關於Android3.2平板上的布局

第一代平板運行於android3.0上,一般是使用xlarge配置后綴(res/layout-xlarge/)來聲明平板布局。為了提供其他類型的平板和屏幕大小----尤其是7寸平板!android3.2引入了一種新的方法來為更多離散的屏幕大小來指定資源。你的布局需要一種新的基於控件容量的技術(例如指定600dp的寬度),而不是試圖使你的布局去適應那些android概括性的分組(例如large或xlarge)

當android去概括大小分組時,對於7寸平板他們也很棘手,因為5寸手機和7寸平板使用同樣的large組。這兩個設備在size上表面上看起來更貼近彼此,但其實UI在相當大程度上還是不同的,用戶體驗的效果也不太好。因此一個7寸和5寸的屏幕將不使用同樣的layout。根據這兩種屏幕你應該盡可能的提供不同的布局,android現在允許我們指定基於寬度或高度layout資源,記住請使用dp單位。

例如, 在你根據平板風格設計布局以后,你可能需要當屏幕小於600dp的寬度時候停止工作。這個界限會因為你的平板布局而變成最小的尺寸。這樣你能立刻指定當至少寬度在600dp時候,layout中的資源文件才被用到。

注意: 記住!dip是一個非常重要的單位,你的布局大小也應該用dp單位。因為它可以看做一種比例單位而非像素那樣的絕對單位。

4.3.1使用新的大小后綴(非密度)

你能為你的布局指定不同的資源配置。在下方的表格2中這些新的后綴提供給你更多的控制,相對於傳統的(small, normal, large, and xlarge)這些已經超過它們了

注意: 你指定使用的這些后綴並非實際的屏幕大小。當然,這些大小是根據寬度(dp單位)和高度(dp單位)被用於activity的window中。window的特殊性在於它方法是有個動作條,用來顯示電池和通知信息的。所以你在設計UI的時候需要考慮 你的應用是否需要顯示動作條。下面我們看下面表格4-2:

屏幕 配置

后綴值

描述

最小寬度

sw<N>dp

例如:
sw600dp
sw720dp

用這個后綴可以確保不管當前屏幕是否橫豎屏。你的應用有一個至少<N>dp的可用寬度 

例如, 如果你的layout一直需求最小屏幕的一邊為600dp,那么你能使用這個后綴創建layout資源(res/layout-sw600dp/)。對於用戶來講,不管600dp是寬還是高,僅當屏幕可用的最小尺寸至少是600dp時,系統會使用這些資源(就是說你的設備不用以什么角度看,長和寬的某一邊的最小值大於或等於600dp時,系統就會使用)。當屏幕水平方向改變時,設備的最小寬度不會改變

設備的最小寬度要考慮屏幕的裝飾和系統UI。例如,如果設備有一些持續不變的沿着你最小寬度的軸方向的UI元素(動作條等),那么系統會宣布最小寬度比實際屏幕寬度要小,因為那些UI元素對於你的UI來說是不可用的

 因為寬度是經常影響布局的一個重要因素,所以使用最小寬度來控制一般的屏幕大小(針對平板)還是有用的。 可用寬度也是決定是否使用單屏幕布局(手機)和多屏幕布局(平板)關鍵因素,因此你很可能關心每一個設備上的最小方面。

屏幕可用寬度

w<N>dp

例如:
w720dp
w1024dp

用dp單位指定一個最小化的在可用寬度下可以使用的資源。系統會根據寬度改變(橫豎屏切換時)來匹配這個值,並反映到當前實際可用的寬度上

當你決定是否使用多屏幕布局時它很有用,因為即使在平板設備上,你也經常不想要多屏幕布局會根據橫豎屏來變化。因此你可以用這個來指定最小化的寬度需求,它可以用來代替方向后綴(land,port)和大小后綴(small,normal,large,xlarge)使之整合到一起。

屏幕可用高度

h<N>dp

例如:
h720dp
h1024dp
etc.

用dp單位指定一個最小化的屏幕高度。和"屏幕可用寬度"類似

表格4-2 android3.2加入的新后綴(注意是基於屏幕大小的而不是密度)

當使用這些后綴時你可能覺得比傳統的那四種后綴復雜些,實際上你用過后就發現它很簡單,它能一次簡化你的UI需求。當你設計UI時,主要的事情就是需要考慮我們App中的實際大小,並且對於手機和平板風格的切換。它取決於你某些特定切換點的設計,可能對於平板布局你需要720dp的寬度,可能600dp就足夠了,或者480,或者這兩個之間。使用表格2的后綴,你可以在布局改變時精確的控制大小。以后我們會根據實際開發來講述的

4.3.2關於實際配置的例子(非密度)

以下是一些屏幕數據:

320dp: 一種手機屏幕(240x320 ldpi, 320x480 mdpi, 480x800 hdpi, 等).

480dp: 一種平板 (480x800 mdpi).

600dp:  7寸平板(600x1024 mdpi).

720dp: 10寸平板(720x1280 mdpi, 800x1280 mdpi, 等).

我們使用表格2中的后綴來為我們的應用定義不同的切換風格(包括手機和平板),例如, 如果我們的平板布局600dp是最小可用寬度,我們能提供兩套布局方式:

res/layout/main_activity.xml           # 手機
res/layout-sw600dp/main_activity.xml   # 平板

這種情況下,屏幕可用的最小寬度為600dp,這是偽了支持平板布局被應用。

或者你可能想要區分7寸和10寸平板,你可以這么做:

res/layout/main_activity.xml           # 手機(比600dp更小的可用寬度)
res/layout-sw600dp/main_activity.xml   # 7寸平板 (600dp的寬度或者更大)
res/layout-sw720dp/main_activity.xml   # 10寸平板(720dp的寬度或者更大)

注意上面的兩套例子的使用使用 sw(最小寬度)后綴,它指定屏幕的兩邊中的最小一邊,不管屏幕的水平方向。它忽視橫豎屏。

然而某些情況下我們需要精確布局。例如如果你有一個 2個面板合並在一起的顯示效果。是否屏幕提供至少600dp的寬度,是否橫豎屏你都要使用它。就應該這:

res/layout/main_activity.xml         # 手機(小於600dp的可用寬度)
res/layout-w600dp/main_activity.xml  #多面板 (任意一個面板都是600dp或者更高的寬度)

注意上面這里用的是w<n>dp。實際設備可能需要兩套布局,它依賴於屏幕的水平方向(一邊至少是600dp的寬度,另一邊小於600dp,你會發現不管橫豎屏都滿足這個條件。所以你需要准備兩套關於橫豎屏的布局)

關於什么是多屏手機或者叫多面板手機。我發個圖給大家看看就明白了(下面這個手機其實有3屏),如圖4-5所示:

 

圖4-5 三屏手機截圖

4.4實踐中應該注意哪些

在多樣的屏幕中我們使用傳統的四種配置還是能很好的獲得支持的。上面我們提供了多種定義的方法。添加這些后綴能確保你的App能適應不同的屏幕設備。下面是一些方法,告訴你如何確保你的應用程序可以正確地顯示在不同的屏幕上:

1.在XML布局文件中請使用wrap_content, fill_parent, 或者 dp 單位

2.在你的程序代碼中最好不要使用像素(px)這種硬編碼

3.不要使用AbsoluteLayout (絕對布局)

4.提供不同的位圖drawable資源來適應不同的屏幕密度.

1. 使用在XML布局文件中請使用wrap_content, fill_parent, 或者 dp 單位

當在XML中為你的Views定義android:layout_width和android:layout_width時,使用"wrap_content","fill_parent"或者dp單位來保證View在當前屏幕上獲得一個合適的大小。

例如,一個view的寬為layout_width="100dp"   在mdpi的屏幕下它是100px,在hdpi的屏幕下它就是150px,但顯示出來的效果在物理屏幕上是一樣的大小

同樣, 對於定義文本的大小,我們應該用sp(scale-independent pixel)。 因為sp和dp的概念是一樣的,它們不是絕對的像素值

2.在你的程序代碼中最好不要使用像素(px)這種硬編碼

由於執行原因並使代碼更簡單,android系統使用像素作為標准單位用來描述尺寸或坐標值。就是說在代碼中android還是使用的像素用來表述尺寸,但它是基於當前屏幕密度的,所以是變化的。如果代碼中 View.getWidth()返回的值是10,這么這個10的單位為像素,但這僅僅是在某一個密度的屏幕上而已,其他不同密度的屏幕上它的結果就會不一樣了。所以android是不建議我們在代碼中用像素來設置布局的,因為它會加重我們的工作量,並且處理的也不一定很好。想象一下這么多屏幕設備你如果用代碼來適配的話,你就得考慮的非常嚴謹了。不過如果你只針對某一種屏幕的話就另當別論了,但這種情況很少見。

3.不要使用AbsoluteLayout (絕對布局)

請不要使用AbsoluteLayout(絕對布局)這種布局是早期android的版本,在android1.5版本的時候就已經廢棄了。雖然為了兼容以前很老的設備這種布局還存在,但目前來說,我們已經完全沒有必要再使用它了。 

4.提供不同的位圖drawable資源來適應不同的屏幕密度

雖然在當前屏幕配置上系統會自動縮放你的layout和drawable資源,但為了優化某些特定密度的設備,可能我們並不想讓它縮放,我們想給這種密度指定一套資源也是可以而且這樣的效果也很不錯,能更好的根據不同的屏幕來調整我們的UI。這個我們在本文中已經反復提到了,目的就是為了加深你的印象。

一個很好的例子就是關於你用eclipse生成android工程的時候,三種不同的drawable(res/drawable-ldpi/icon.png,res/drawable-mdpi/icon.png,res/drawable-hdpi/icon.png)中都

會自動生成不同尺寸的icon.png。

注意: 如果我們沒有定義某個后綴,但屏幕密度又是需要那個后綴的話,那么系統會假定你的資源都是基於mdpi(默認)的。並會放縮你的資源

4.5 關於密度額外的注意事項

這一段主要描述android在不同屏幕密度上是怎么縮放位圖drawable的,我們需要更進一步的掌握系統控制位圖資源的原理。當在運行時操作圖形,我們能更好的理解它是怎樣支持多屏幕的,我們應該了解下系統是如何保證適應屏幕並適當的縮放位圖的:

1.載入時自動縮放 (比如位圖drawables)。

基於當前屏幕的密度,系統使用任意大小或者密度的資源來顯示它們的時候是沒有縮放過的。如果在當前密度下沒有可用的資源,那么系統會載入默認資源並等比縮放它們來匹配當前屏幕的密度。除非有有針對密度的后綴出現,不然系統都是認為默認資源(沒有后綴的drawable)是為mdpi的密度來設計的。因此系統這個時候會調整位圖的大小來適應屏幕。

如果你需求資源縮放之前的大小,那系統實際上返回的是縮放后的大小。例如:如果你沒有指定hdpi后綴,一個在mdpi下50px*50px的位圖在一個hdpi下會縮放為75px*75px。在hdpi屏幕下系統會返回這個75px這個大小。如果你不希望系統根據不同的密度來縮放資源,那么請記住使用“res/drawable-nodpi/”

2.運行時自動縮放(比如像素的大小和坐標)

一個應用能關閉載入時自動縮放的這個功能,只要你在manifest中設置android:anyDensity ="false",或者在程序中使用BitmapFactory.Options.inScaled返回的值為false。在這種情況下。系統會在繪制的時候自動等比縮放任何絕對坐標和像素大小。這么做確保用針對像素的屏幕元素能一直顯示。系統會處理縮放,然后轉化並報告縮放的像素大小,而不是物理像素大小。下面我們來舉個例子:例如,假設一個設備有一個WVGA(800*480)下是hdpi的屏幕,並且它和在傳統的HVGA(480*320)屏幕一樣的物理大小,但執行應用的時候關閉了載入時自動縮放這個功能。這樣的話,當系統查詢屏幕大小時,它會報告一個320*533的大小,為什么會是320*533呢,我們開的模擬器是800*480的啊!!因為系統在繪制的時候縮放了。系統報告的是縮放后的像素大小,而不是我們模擬器上的物理大小。然后App需要繪制操作時,本來想在(10,10)上的位置繪制,但會變成(15,15)。如果你的應用直接操作縮放位圖,那這種差異可能導致意外的行為。以前很多剛開始接觸android的朋友經常會遇到系統報告320*533的這種問題。原因就是由於我們關閉了載入時自動縮放這個功能。你關閉了它的話,它就會在運行時縮放並返回結果。所以我們要檢查manifest中是否設置android:anyDensity ="false"。如果有趕快去掉。也許還有朋友發現沒有設置怎么也會出現這種問題,這是由於以前比較老的SDK版本系統默認設置關閉了載入時自動縮放這個功能導致的,不過目前這種情況很少發生了。 

4.5.1運行時創建縮放的位圖對象

我們的應用如果需要在內存中創建一個位圖(bitmap)對象,那么系統會認為你是基於mdpi密度的屏幕來創建的。默認的,系統會根據屏幕密度在繪制的時候自動縮放這個位圖。當位圖沒有指定密度屬性時候,系統會自動縮放。為了控制位圖在運行時創建后是否被縮放,我們可以指定位圖的密度屬性,使用Bitmap.setDensity()。具體的值可以傳DisplayMetrics.DENSITY_HIGH或其他。我們還可以從文件或者一個流中使用BitmapFactory來創建位圖,使用BitmapFactory.Options來定義位圖的屬性,那么系統會根據你的屬性來縮放它。我們還可以使用BitmapFactory.Options.inDensity來指定這個位圖是否需要匹配當前的屏幕密度。如果我們設置BitmapFactory.Options.inDensity=false;那么系統在載入位圖時將不會自動縮放它,只會在運行時縮放它。使用運行時縮放CPU占用率高,內存占用低。使用載入時縮放CPU占用率低,內存占用高。如何取舍就看你的需求了。

4.5.2 dp和像素的轉換

有些情況下,dp和px只需要相互轉換的。例如一個應用在用手指滑動屏幕的時候會感應用戶的手指移動了多少個像素。在一個normal和mdpi的屏幕下,用戶必須移動16px/160dpi,等價於十分之一英寸(大約2.5mm(毫米))。那么在一個hdpi(240dpi)的屏幕上用戶必須移動16px/20dpi,等價十五分之一英寸(1.7mm)。距離是很短的,因此這對用來說會很敏感。為了修復這個問題,需要用代碼吧dp轉換成px單位。例如:

 

// 手勢的響應的范圍(dp)

privatestaticfinalfloat GESTURE_THRESHOLD_DP =16.0f// 獲取屏幕的密度來縮放

finalfloat scale =getResources().getDisplayMetrics().density;

//根據密度吧dp轉換成px

mGestureThreshold =(int)(GESTURE_THRESHOLD_DP * scale +0.5f);

// 可以使用這個響應的范圍了

 

 

這里DisplayMetrics.density的值為(0.75[ldpi],1[mdpi],1.5[hdpi],2[xhdpi]) ,其實我們還可以使用ViewConfiguration類來處理,但前提是打開了載入時縮放這個功能(目前來說,默認都

是開的不用擔心)並且我們可以使用ViewConfiguration.getScaledTouchSlop()來直接獲得換算距離。具體使用如下:

private static final int GESTURE_THRESHOLD_DP =ViewConfiguration.get(myContext).getScaledTouchSlop();

 

4.6 如何在多種屏幕下測試我們的應用

首先我們來看一下圖4-6,這是使用AVD工具設置虛擬設備的截圖

 

圖4-6 這是android SDK中的AVD工具,它提供一套虛擬機設備。(最后1,2章會詳細講述使用方法)

在發布我們的應用之前,我應該在不同的屏幕大小和密度上測試我們的App。android SDK中有很多模擬器,我們可以修改模擬器上的默認的大小,密度,分辨率來整合測試。例如使用android2.1版本的模擬器,我們可以同時新建多個2.1的版本,但每個的密度不同。這么多模擬器可以為我們省下很多錢來買不同的手機。如果你想修改某個模擬器的密度,你只需要選中它點擊右邊的edit就可以修改了。如下圖4-7所示:(這里只需要留點印象后面會有章節單獨的講述AVD參數配置)

 

圖4-7 在AVD中點擊edit后的截圖

為了測試應用是否支持多種不同的屏幕,我們應該創建一系列的AVD(android virtual devices)。如果不用eclipse的話,我們可以在sdk目錄下執行SDK Manager.exe這樣就顯示出圖4-6的界面。

4.7 本章小節

關於android的屏幕和分辨率,這是非常重要的一個知識點,希望大家認真學好它,在以后的開發過程中絕對是非常有幫助。現在我們稍微回顧一下關鍵的內容:

一,Boss的5個關鍵點

1.boss的體型(屏幕大小)

2.boss的模型細粒度(屏幕密度)

3.我們看boss的角度(屏幕的方向)

4.boss的總體外觀和風格(屏幕的分辨率)

5.boss的傷害公式(dp單位)

二,我們也有相應的對策對付他們

drawable(我們游戲角色的技能,目前4種(ldpi,mdpi,hdpi,xhdpi))

layout(我們游戲角色的裝備,目前4種(small,normal,large,extra large))

三,怎么樣搞定這些boss

manifest文件中指出你的App支持的屏幕大小

根據不同的屏幕大小提供不同的布局

根據不同的屏幕密度提供不同的位圖

四,最后我們需要熟悉后綴和一些公式(就像游戲boss的攻略)

目前那么多后綴不需要完全記住(以后用的多自然就記住了),但需要有個印象(后綴可以為drawable服務,也可以為layout服務,你可以想象成后綴是一種附魔提升裝備(layout)的屬性,又是一種銘文用來提高技能(drawable)傷害或效果)

還記得3:4:6:8嗎? 還記得 0.75x, x ,1.5x, 2x嗎?這些都很重要哦

本文來自jy02432443,QQ78117253。轉載請保留出處,並保留追究法律責任的權利


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM