1、基本概念
屏幕大小(screen size) – 屏幕的實際大小,用屏幕對角線長度來衡量(比如3.4寸,3.8寸)。android把屏幕分爲以下4種:small,normal,large,extra large。
怎麼判斷?
屏幕密度(Screen Density) - 一塊實際的屏幕區域有多少個像素,一般用dpi衡量(每英寸有多少個點)。相比起medium、high屏幕密度的設備,在一塊確定大小的屏幕區域l密度爲low的屏幕擁有的像素更少。android把屏幕密度分爲4種:low,medium,high,extra high。
如何判斷是ldpi,mdpi,hdpi?
方向(orientation) - 屏幕方向分爲landscape(橫屏)和portrait(豎屏)。
分辨率(Resolution) - 屏幕上的總實際像素數。對屏幕進行適配時,一般不關注它的分辨率,只關注它的屏幕大小和密度。
與密度無關的像素(Density-independent pixel,dp或dip) - 爲了保證你的UI適合不同的屏幕密度,建議你採用dp來定義程序UI。
它的計算方法爲:px = dp * (dpi / 160)
sp(scale-independent pixel)
如何分辨一個屏幕是ldpi、mdpi、hdpi的方法,見下圖
2、怎樣適配多種屏幕
a.在manifest裏定義你的程序支持的屏幕類型,相應代碼如下:
<supports-screens android:resizeable=["true"| "false"]
android:smallScreens=["true" | "false"] //是否支持小屏
android:normalScreens=["true" | "false"] //是否支持中屏
android:largeScreens=["true" | "false"] //是否支持大屏
android:xlargeScreens=["true" | "false"] //是否支持超大屏
android:anyDensity=["true" | "false"] //是否支持多種不同密度的屏幕
android:requiresSmallestWidthDp=”integer”
android:compatibleWidthLimitDp=”integer”
android:largestWidthLimitDp=”integer”/>
b.對不同大小的屏幕提供不同的layout。
比如,如果需要對大小爲large的屏幕提供支持,需要在res目錄下新建一個文件夾layout-large/並提供layout。當然,也可以在res目錄下建立layout-port和layout-land兩個目錄,裏面分別放置豎屏和橫屏兩種佈局文件,以適應對橫屏豎屏自動切換。
c.對不同密度的屏幕提供不同的圖片。
應儘量使用點9格式的圖片,如需對密度爲low的屏幕提供合適的圖片,需新建文件夾drawable-ldpi/,並放入合適大小的圖片。相應的,medium對應drawable-mdpi /,high對應drawable-hdpi/,extra high對應drawable-xhdpi/。
圖片大小的確定:low:medium:high:extra high比例爲3:4:6:8。舉例來說,對於中等密度(medium)的屏幕你的圖片像素大小爲48×48,那麼低密度(low)屏幕的圖片大小應爲36×36,高(high)的爲72×72,extra high爲96×96。
3、多屏幕適配的4條黃金原則
a.在layout文件中設置控件尺寸時應採用wrap_content,fill_parent和dp。
具體來說,設置view的屬性android:layout_width和android:layout_height的值時,wrap_content,fill_parent或dp比pix更好。相應地,爲了使文字大小更好的適應屏幕應該使用sp來定義文字大小。
b.在程序的代碼中不要出現具體的像素值。
爲了使代碼簡單,android內部使用pix爲單位表示控件的尺寸,但這是基於當前屏幕基礎上的。爲了適應多種屏幕,android建議開發者不要使用具體的像素來表示控件尺寸。
c.不要使用AbsoluteLayout(android1.5已廢棄) 。相應地,應使用RelativeLayout。
d.對不同的屏幕提供合適大小的圖片。見上面第2部分。
4、需要注意的地方
以上設置適用於android3.2以下的版本。(本人目前開發是在android2.2上,這部分以後再補充)
5、怎樣測試你的程序是否支持多屏幕適配
一般使用AVD Manager創建多個不同大小的模擬器,如下圖
6、參考文檔:http://developer.android.com/guide/practices/screens_support.html
Android多屏幕適配
問題:
測試時,發現應用在不同的顯示器上顯示效果不同(部分文本不能顯示完全),自然想到屏幕適配的問題。
按照思路整理如下:
(一) 幾個概念
1, Screen size 屏幕的尺寸,即對角線長度(單位inch-英寸)
2, Screen density屏幕密度,即單位長度像素點數(pots/inches)
3, Resolution 分辨率,即屏幕的總像素點數(width * height)
4, Density-independent pixel (dp)獨立像素密度。標準是160dip.即1dp對應1個pixel,計算公式如:px = dp * (dpi / 160),屏幕密度越大,1dp對應 的像素點越多。
(二) 屏幕的分類(size & density)
1, 以總像素數分,文本的size等都要改,如下圖所示
每一個分類都有其最小分辨率,如下,可根據分辨率劃分種類:
2, 以屏幕密度分,提供不同的圖片如下圖所示
Note1:匹配以上面兩種爲參考。
Note2:還有專爲水平(landscape)和豎直(portrait)兩種,使用的少,在此不贅述。
(三) Android尋找最佳資源原理
1, 排除與設備設置不符合的資源
2, 根據限定詞(qualifier)的優先級,按照順序查找
3, 在限定詞下,是否存在資源路徑
4, 排除不包含在限定詞中的資源路徑
5, 繼續執行不同的限定詞查找,直到找到相應的資源
如下圖所示:
(四) 項目步驟:
1, manufest中配置
- <supports-screens
- android:anyDensity="true"
- android:largeScreens="true"
- android:normalScreens="true"
- android:smallScreens="true"
- android:xlargeScreens="true" />
2, 新建對應的資源文件夾
A, Layout
例如,我現在有三個顯示器分辨率:
分別爲1280*720,1024*768,1200*690
根據以上最低分辨率的要求,分爲xlarge和large兩類,新建兩個文件夾,如下:
如下圖所示:
B, Drawable
如下圖所示:
在drawable中,以mdpi爲標準(即160dpi)。比例保持爲3:4:5:6,如下圖所示:
本文出自 “小新專欄” 博客,請務必保留此出處http://mikewang.blog.51cto.com/3826268/865304
Android 多屏幕支持
另外一篇
http://blog.csdn.net/zj_133/article/details/7281140
多國語言文件夾
http://guojianhui0906.iteye.com/blog/1271827
1.術語和概念
術語 |
說明 |
備註 |
Screen size(屏幕尺寸) |
指的是手機實際的物理尺寸,比如常用的2.8英寸,3.2英寸,3.5英寸,3.7英寸(對角線長度) |
摩托羅拉milestone手機是3.7英寸 |
Aspect Ratio(寬高比率) |
指的是實際的物理尺寸寬高比率,分爲long和nolong |
Milestone是16:9,屬於long |
Resolution(分辨率) |
和電腦的分辨率概念一樣,指手機屏幕縱、橫方向像素個數 |
Milestone是854*480 |
DPI(dot per inch) |
每英寸像素數,如120dpi,160dpi等,假設QVGA(320*240)分辨率的屏幕物理尺寸是(2英寸*1.5英寸),dpi=160 所以dpi = 分辨率的高寬的平方根(對角線)除以物理尺寸高寬的平方根(對角線). |
可以反映屏幕的清晰度,用於縮放UI的 |
Density(密度) |
屏幕裏像素值濃度,resolution/Screen size可以反映出手機密度, (dpi/160) |
|
Density-independent pixel (dip) |
指的是邏輯密度計算單位,dip和具體像素值的對應公式是pixel/dip=dpi值/160,也就是pixel = dip * (dpi / 160) |
Px (Pixel像素: 不同設備顯示效果相同。這裏的“相同”是指像素數不會變,比如指定UI長度是100px,那不管分辨率是多少UI長度都是100px。也正是因爲如此才造成了UI在小分辨率設備上被放大而失真,在大分辨率上被縮小。
2. DPI值計算
比如:計算WVGA(800*480)分辨率,3.7英寸的密度DPI,如圖1所示
圖1
Diagonal pixel表示對角線的像素值(=),DPI=933/3.7=252
3.手機屏幕的分類
3.1根據手機屏幕密度(DPI)或屏幕尺寸大小分爲以下3類,如圖2所示
圖2
3. 2手機屏幕分類和像素密度的對應關係如表1所示:
Low density (120), ldpi |
Medium density (160), mdpi |
High density (240), hdpi |
|
Small screen |
QVGA (240x320) |
||
Normal screen |
WQVGA400 (240x400)WQVGA432 (240x432) |
HVGA (320x480) |
WVGA800 (480x800)WVGA854 (480x854) |
Large screen |
WVGA800* (480x800)WVGA854* (480x854) |
表1
3.3手機尺寸分佈情況(http://developer.android.com/resources/dashboard/screens.html)如圖3所示,目前主要是以分辨率爲800*480和854*480的手機用戶居多
圖3
從以上的屏幕尺寸分佈情況上看,其實手機只要考慮3-4.5寸之間密度爲1和1.5的手機
4 UI設計
從開發角度講,應用程序會根據3類Android手機屏幕提供3套UI佈局文件,但是相應界面圖標也需要提供3套,如表2所示
Icon Type |
Standard Asset Sizes (in Pixels), for Generalized Screen Densities |
||
Low density screen (ldpi) |
Medium density screen (mdpi) |
High density screen (hdpi) |
|
Launcher |
36 x 36 px |
48 x 48 px |
72 x 72 px |
Menu |
36 x 36 px |
48 x 48 px |
72 x 72 px |
Status Bar |
24 x 24 px |
32 x 32 px |
48 x 48 px |
Tab |
24 x 24 px |
32 x 32 px |
48 x 48 px |
Dialog |
24 x 24 px |
32 x 32 px |
48 x 48 px |
List View |
24 x 24 px |
32 x 32 px |
48 x 48 px |
表2
5 如何做到自適應屏幕大小呢?
1)界面佈局方面
需要根據物理尺寸的大小準備5套佈局,layout(放一些通用佈局xml文件,比如界面中頂部和底部的佈局,不會隨着屏幕大小變化,類似windos窗口的title bar),layout-small(屏幕尺寸小於3英寸左右的佈局),layout-normal(屏幕尺寸小於4.5英寸左右),layout-large(4英寸-7英寸之間),layout-xlarge(7-10英寸之間)
2)圖片資源方面
需要根據dpi值準備5套圖片資源,drawable,drawalbe-ldpi,drawable-mdpi,drawable-hdpi,drawable-xhdpi
Android有個自動匹配機制去選擇對應的佈局和圖片資源
四種屏幕尺寸分類:: small, normal, large, and xlarge
四種密度分類: ldpi (low), mdpi (medium), hdpi (high), and xhdpi (extra high)
需要注意的是: xhdpi是從 Android 2.2 (API Level 8)纔開始增加的分類.
xlarge是從Android 2.3 (API Level 9)纔開始增加的分類.
DPI是“dot per inch”的縮寫,每英寸像素數。
一般情況下的普通屏幕:ldpi是120,mdpi是160,hdpi是240,xhdpi是320。
兩種獲取屏幕分辨率信息的方法:
DisplayMetrics metrics = new DisplayMetrics();
Display display = activity.getWindowManager().getDefaultDisplay();
display.getMetrics(metrics);
//這裏得到的像素值是設備獨立像素dp
//DisplayMetrics metrics=activity.getResources().getDisplayMetrics(); 這樣獲得的參數信息不正確,不要使用這種方式。
不能使用android.content.res.Resources.getSystem().getDisplayMetrics()。這個得到的寬和高是空的。
如果需要爲Android pad定製資源文件,則res目錄下的目錄可能爲:
drawable
drawable-ldpi
drawable-mdpi
drawable-hdpi
drawable-xhdpi
drawable-nodpi
drawable-nodpi-1024×600
drawable-nodpi-1280×800
drawable-nodpi-800×480
values
values-ldpi
values-mdpi
values-hdpi
values-xhdpi
values-nodpi
values-nodpi-1024×600
values-nodpi-1280×800
values-nodpi-800×480
源碼庫 » Android » res
路徑:android-4.0.1/packages/SystemUI/res
上一級 目 錄
- [anim]
- [drawable]
- [drawable-hdpi]
- [drawable-large-hdpi]
- [drawable-large-mdpi]
- [drawable-large-xhdpi]
- [drawable-mdpi]
- [drawable-nodpi]
- [drawable-sw600dp-hdpi]
- [drawable-sw600dp-mdpi]
- [drawable-sw600dp-xhdpi]
- [drawable-xhdpi]
- [layout]
- [layout-land]
- [layout-port]
- [layout-sw600dp]
- [menu]
- [values]
- [values-af]
- [values-af-land]
- [values-af-large]
- [values-am]
- [values-am-land]
- [values-am-large]
- [values-ar]
- [values-ar-land]
- [values-ar-large]
- [values-ar-port]
- [values-bg]
- [values-bg-land]
- [values-bg-large]
- [values-bg-port]
- [values-ca]
- [values-ca-land]
- [values-ca-large]
- [values-ca-port]
- [values-cs]
- [values-cs-land]
- [values-cs-large]
- [values-da]
- [values-da-land]
- [values-da-large]
- [values-de]
- [values-de-land]
- [values-de-large]
- [values-el]
- [values-el-land]
- [values-el-large]
- [values-en-rGB]
- [values-en-rGB-land]
- [values-en-rGB-large]
- [values-en-rGB-port]
- [values-es]
- [values-es-land]
- [values-es-large]
- [values-es-rUS]
- [values-es-rUS-land]
- [values-es-rUS-large]
- [values-fa]
- [values-fa-land]
- [values-fa-large]
- [values-fa-port]
- [values-fi]
- [values-fi-land]
- [values-fi-large]
- [values-fi-port]
- [values-fr]
- [values-fr-land]
- [values-fr-large]
- [values-hdpi]
- [values-hi]
- [values-hi-land]
- [values-hi-large]
- [values-hr]
- [values-hr-land]
- [values-hr-large]
- [values-hr-port]
- [values-hu]
- [values-hu-land]
- [values-hu-large]
- [values-hu-port]
- [values-in]
- [values-in-land]
- [values-in-large]
- [values-in-port]
- [values-it]
- [values-it-land]
- [values-it-large]
- [values-iw]
- [values-iw-land]
- [values-iw-large]
- [values-iw-port]
- [values-ja]
- [values-ja-land]
- [values-ja-large]
- [values-ko]
- [values-ko-land]
- [values-ko-large]
- [values-land]
- [values-large]
- [values-large-port]
- [values-lt]
- [values-lt-land]
- [values-lt-large]
- [values-lt-port]
- [values-lv]
- [values-lv-land]
- [values-lv-large]
- [values-lv-port]
- [values-ms]
- [values-ms-land]
- [values-ms-large]
- [values-nb]
- [values-nb-land]
- [values-nb-large]
- [values-nl]
- [values-nl-land]
- [values-nl-large]
- [values-pl]
- [values-pl-land]
- [values-pl-large]
- [values-port]
- [values-pt]
- [values-pt-land]
- [values-pt-large]
- [values-pt-rPT]
- [values-pt-rPT-land]
- [values-pt-rPT-large]
- [values-rm]
- [values-ro]
- [values-ro-land]
- [values-ro-large]
- [values-ro-port]
- [values-ru]
- [values-ru-land]
- [values-ru-large]
- [values-sk]
- [values-sk-land]
- [values-sk-large]
- [values-sk-port]
- [values-sl]
- [values-sl-land]
- [values-sl-large]
- [values-sl-port]
- [values-sr]
- [values-sr-land]
- [values-sr-large]
- [values-sr-port]
- [values-sv]
- [values-sv-land]
- [values-sv-large]
- [values-sw]
- [values-sw-land]
- [values-sw-large]
- [values-sw600dp]
- [values-sw600dp-port]
- [values-sw720dp]
- [values-sw720dp-port]
- [values-th]
- [values-th-land]
- [values-th-large]
- [values-th-port]
- [values-tl]
- [values-tl-land]
- [values-tl-large]
- [values-tl-port]
- [values-tr]
- [values-tr-land]
- [values-tr-large]
- [values-uk]
- [values-uk-land]
- [values-uk-large]
- [values-uk-port]
- [values-vi]
- [values-vi-land]
- [values-vi-large]
- [values-vi-port]
- [values-xhdpi]
- [values-zh-rCN]
- [values-zh-rCN-land]
- [values-zh-rCN-large]
- [values-zh-rTW]
- [values-zh-rTW-land]
- [values-zh-rTW-large]
- [values-zu]
- [values-zu-land]
- [values-zu-large]
android中獲取屏幕的長於寬,參考了網上有很多代碼,但結果與實際不符,如我的手機是i9000,屏幕大小是480*800px,得到的結果卻爲320*533
結果很不靠譜,於是自己寫了幾行代碼,親測一下
測試參數:
測試環境: i9000(三星)
物理屏幕:480*800px
density :1.5
測試代碼:
- // 獲取屏幕密度(方法1)
- int screenWidth = getWindowManager().getDefaultDisplay().getWidth(); // 屏幕寬(像素,如:480px)
- int screenHeight = getWindowManager().getDefaultDisplay().getHeight(); // 屏幕高(像素,如:800p)
- Log.e(TAG + " getDefaultDisplay", "screenWidth=" + screenWidth + "; screenHeight=" + screenHeight);
- // 獲取屏幕密度(方法2)
- DisplayMetrics dm = new DisplayMetrics();
- dm = getResources().getDisplayMetrics();
- float density = dm.density; // 屏幕密度(像素比例:0.75/1.0/1.5/2.0)
- int densityDPI = dm.densityDpi; // 屏幕密度(每寸像素:120/160/240/320)
- float xdpi = dm.xdpi;
- float ydpi = dm.ydpi;
- Log.e(TAG + " DisplayMetrics", "xdpi=" + xdpi + "; ydpi=" + ydpi);
- Log.e(TAG + " DisplayMetrics", "density=" + density + "; densityDPI=" + densityDPI);
- screenWidth = dm.widthPixels; // 屏幕寬(像素,如:480px)
- screenHeight = dm.heightPixels; // 屏幕高(像素,如:800px)
- Log.e(TAG + " DisplayMetrics(111)", "screenWidth=" + screenWidth + "; screenHeight=" + screenHeight);
- // 獲取屏幕密度(方法3)
- dm = new DisplayMetrics();
- getWindowManager().getDefaultDisplay().getMetrics(dm);
- density = dm.density; // 屏幕密度(像素比例:0.75/1.0/1.5/2.0)
- densityDPI = dm.densityDpi; // 屏幕密度(每寸像素:120/160/240/320)
- xdpi = dm.xdpi;
- ydpi = dm.ydpi;
- Log.e(TAG + " DisplayMetrics", "xdpi=" + xdpi + "; ydpi=" + ydpi);
- Log.e(TAG + " DisplayMetrics", "density=" + density + "; densityDPI=" + densityDPI);
- int screenWidthDip = dm.widthPixels; // 屏幕寬(dip,如:320dip)
- int screenHeightDip = dm.heightPixels; // 屏幕寬(dip,如:533dip)
- Log.e(TAG + " DisplayMetrics(222)", "screenWidthDip=" + screenWidthDip + "; screenHeightDip=" + screenHeightDip);
- screenWidth = (int)(dm.widthPixels * density + 0.5f); // 屏幕寬(px,如:480px)
- screenHeight = (int)(dm.heightPixels * density + 0.5f); // 屏幕高(px,如:800px)
- Log.e(TAG + " DisplayMetrics(222)", "screenWidth=" + screenWidth + "; screenHeight=" + screenHeight);
結果如下:
- E/== MyScreenActivity =================================== getDefaultDisplay( 8509): screenWidth=320; screenHeight=533
- E/== MyScreenActivity =================================== DisplayMetrics( 8509): xdpi=156.3077; ydpi=157.51938
- E/== MyScreenActivity =================================== DisplayMetrics( 8509): density=1.0; densityDPI=160
- E/== MyScreenActivity =================================== DisplayMetrics(111)( 8509): screenWidth=320; screenHeight=533
- E/== MyScreenActivity =================================== DisplayMetrics( 8509): xdpi=234.46153; ydpi=236.27907
- E/== MyScreenActivity =================================== DisplayMetrics( 8509): density=1.5; densityDPI=240
- E/== MyScreenActivity =================================== DisplayMetrics(222)( 8509): screenWidthDip=320; screenHeightDip=533
- E/== MyScreenActivity =================================== DisplayMetrics(222)( 8509): screenWidth=480; screenHeight=800
分析結果:
在onDraw()方法中
方法1和2,得到的結果都一致,均爲320*533,明顯不是測試機i9000的屏幕大小
方法3,將方法1和2得到的結果,乘以density後,完美的480*800,perfect!
注:density 大於1的情況下,需要設置targetSdkVersion在4-9之間,例如
<uses-sdk android:minSdkVersion="3" android:targetSdkVersion="10" />
但是,這就說明方法3一定是通用的嗎?
回答是否定的,因爲我也在模擬器、HTC G14物理機,以及ViewSonic、Galaxy平板上測試過,方法3在density=1.5時,放大了實際屏幕值,例如:HTC G14
在HTC G14上,實際屏幕大小,直接通過dm.widthPixels、dm.heightPixels便得到了實際物理屏幕大小(540,960)
導致無法通過一種通用的方法獲取真實物理屏幕大小的原因,可能就是因爲Android系統開源,不同的手機生產廠商沒有統一的製造標準,來規定手機屏幕。
仔細分析代碼,發現問題出在代碼:
getWindowManager().getDefaultDisplay().getMetrics(dm)
Initialize a DisplayMetrics object from this display's data.
dm = getResources().getDisplayMetrics()
Return the current display metrics that are in effect for this resource object. The returned object should be treated as read-only.
手機尺寸分佈情況(http://developer.android.com/resources/dashboard/screens.html)如圖所示,
目前主要是以分辨率爲800*480和854*480的手機用戶居多
從以上的屏幕尺寸分佈情況上看,其實手機只要考慮3-4.5寸之間密度爲1和1.5的手機
2、android多屏幕支持機制
Android的支持多屏幕機制即用爲當前設備屏幕提供一種合適的方式來共同管理並解析應用資源。
Android平臺中支持一系列你所提供的指定大小(size-specific),指定密度(density-specific)的合適資源。
指定大小(size-specific)的合適資源是指small, normal, large, and xlarge。
指定密度(density-specific)的合適資源,是指ldpi (low), mdpi (medium), hdpi(high), and xhdpi (extra high).
Android有個自動匹配機制去選擇對應的佈局和圖片資源
1)界面佈局方面
2)圖片資源方面
Android有個自動匹配機制去選擇對應的佈局和圖片資源。
系統會根據機器的分辨率來分別到這幾個文件夾裏面去找對應的圖片。
在開發程序時爲了兼容不同平臺不同屏幕,建議各自文件夾根據需求均存放不同版本圖片。
3、AndroidManifest.xml 配置
ndroid從1.6和更高,Google爲了方便開發者對於各種分辨率機型的移植而增加了自動適配的功能
3.1是否支持多種不同密度的屏幕
android:anyDensity=["true" | "false"]
如果android:anyDensity="true"
指應用程序支持不同密度,會根據屏幕的分辨率自動去匹配。
如果android:anyDensity="false"
應用程序支持不同密度,系統自動縮放圖片尺寸和這個圖片的座標。具體解釋一下系統是如何自動縮放資源的。
例如我們在hdpi,mdpi,ldpi文件夾下擁有同一種資源,那麼應用也不會自動地去相應文件夾下尋找資源,這種情況都是出現在高密度,以及低密度的手機上,比如說一部240×320像素的手機,
如果設置android:anyDensity="false",Android系統會將240 x 320(低密度)轉換爲320×480(中密度),這樣的話,應用就會在小密度手機上加載mdpi文件中的資源。
3.2是否支持大屏幕
android:largeScreens=["true" | "false"]
如果在聲明不支持的大屏幕,而這個屏幕尺寸是larger的話,系統使用尺寸爲("normal")和密度爲("medium)顯示,
不過會出現一層黑色的背景。
3.3是否支持小屏幕
android:smallScreens=["true" | "false"]
如果在聲明不支持的小屏幕,而當前屏幕尺寸是smaller的話,系統也使用尺寸爲("normal")和密度爲("medium)顯示
如果應用程序能在小屏幕上正確縮放(最低是small尺寸或最小寬度320dp),那就不需要用到本屬性。否則,就應該爲最小屏幕寬度標識符設置本屬性
來匹配應用程序所需的最小尺寸。
4、Android提供3種方式處理屏幕自適應
4.1預縮放的資源(基於尺寸和密度去尋找圖片)
1)如果找到相應的尺寸和密度,則利用這些圖片進行無縮放顯示。
2)如果沒法找到相應的尺寸,而找到密度,則認爲該圖片尺寸爲 "medium",利用縮放顯示這個圖片。
3)如果都無法匹配,則使用默認圖片進行縮放顯示。默認圖片默認標配 "medium" (160)。
4.2自動縮放的像素尺寸和座標(密度兼容)
1)如果應用程序不支持不同密度android:anyDensity="false",系統自動縮放圖片尺寸和這個圖片的座標。
2)對於預縮放的資源,當android:anyDensity="false",也不生效。
3)android:anyDensity="false",只對密度兼容起作用,尺寸兼容沒效果
4.3兼容更大的屏幕和尺寸(尺寸兼容)
1)對於你在聲明不支持的大屏幕,而這個屏幕尺寸是normal的話,系統使用尺寸爲
2.)對於你在聲明不支持的大屏幕,而這個屏幕尺寸是larger的話,系統同樣使用尺寸爲("normal")和密度爲("medium)顯示,
不過會出現一層黑色的背景。
5、Android系統自動適配技巧
Android系統採用下面兩種方法來實現應用的自動適配:
1)佈局文件中定義長度的時候,最好使用wrap_content,fill_parent, 或者dp進行描述,這樣可以保證在屏幕上面展示的時候有合適的大小
2)爲不同屏幕密度的手機,提供不同的位圖資源,可以使得界面清晰無縮放。
對應bitmap資源來說,自動的縮放有時會造成放大縮小後的圖像變得模糊不清,這是就需要應用爲不同屏幕密度配置提供不同的資源:爲高密度的屏幕提供高清晰度的圖像等。
3)不要使用AbsoluteLayout
4)像素單位都使用DIP,文本單位使用SP
6、在代碼中獲取屏幕像素、屏幕密度
DisplayMetrics metric = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metric);
int width = metric.widthPixels;
int height = metric.heightPixels;
float density = metric.density;
int densityDpi = metric.densityDpi;
7、 一般多分辨率處理方法及其缺點
7.1 圖片縮放
基於當前屏幕的精度,平臺自動加載任何未經縮放的限定尺寸和精度的圖片。如果圖片不匹配,平臺會加載默認資源並且在放大或者縮小之後可以滿足當前界面的顯示要求。例如,當前爲高精度屏幕,平臺會加載高精度資源(如HelloAndroid中drawable-hdpi中的位圖資源),如果沒有,平臺會將中精度資源縮放至高精度,導致圖片顯示不清晰。
7.2 自動定義像素尺寸和位置
如果程序不支持多種精度屏幕,平臺會自動定義像素絕對位置和尺寸值等,這樣就能保證元素能和精度160的屏幕上一樣能顯示出同樣尺寸的效果。例如,要讓WVGA 高精度屏幕和傳統的HVGA屏幕一樣顯示同樣尺寸的圖片,當程序不支持時,系統會對程序慌稱屏幕分辨率爲320×480,在(10,10)到(100,100)的區域內繪製圖形完成之後,系統會將圖形放大到(15,15)到(150,150)的屏幕顯示區域。
7.3 兼容更大尺寸的屏幕
當前屏幕超過程序所支持屏幕的上限時,定義supportsscreens元素,這樣超出顯示的基準線時,平臺在此顯示黑色的背景圖。例如,WVGA中精度屏幕上,如程序不支持這樣的大屏幕,系統會謊稱是一個320×480 的,多餘的顯示區域會被填充成黑色。
7.4 採用OpenGL 動態繪製圖片
Android 底層提供了OpenGL的接口和方法,可以動態繪製圖片,但是這種方式對不熟悉計算機圖形學的開發者來講是一個很大的挑戰。一般開發遊戲,採用OpenGL方式。
7.5 多個apk 文件
Symbian 和傳統的J2ME就是採用這種方式,爲一款應用提供多個分辨率版本,用戶根據自己的需求下載安裝相應的可執行文件。針對每一種屏幕單獨開發應用程序不失爲一種好方法,但是目前GoogleMarket 對一個應用程序多個分辨率版本的支持還不完善,開發者還是需要儘可能使用一個apk 文件適應多個分辨率。
本文歡迎轉載,但請註明作者與出處:
作者:流星
出處:http://blog.sina.com.cn/staratsky
Android的支持多屏幕的原理是一套內置的兼容性特徵,即用爲當前設備屏幕提供一種合適的方式來共同管理並解析應用資源。雖然android平臺負責大部分解析應用的工作,但是也爲開發者提供瞭如何控制應用呈現的兩個關鍵方法,它們的使用方法如下:
Android平臺中支持一系列你所提供的指定大小(size-specific),指定密度(density-specific)的合適資源。指定大小(size-specific)的合適資源是指small
, normal
, large
,
and xlarge。
指定密度(density-specific)的合適資源,是指ldpi
(low), mdpi
(medium), hdpi
(high),
and xhdpi
(extra high).
Android平臺還提供 <supports-screens>
manifest文件節點元素,它的屬性包括: android:smallScreens
,
android:normalScreens
, android:largeScreens
,
and android:xlargeScreens.
它可以用來指定應用程序支持哪些尺寸屏幕。
<supports-screens>節點另外一個屬性
android:anyDensity可以用來指定應用程序是否支持內置支持多密度屏幕的機制。
在應用程序運行的時候,android平臺將提供三種方式支持應用程序,以確保應用程序以儘可能好的效果呈現在當前設備屏幕上,這三種具體方式如下:
1、預前縮放(pro-scaling)資源(如圖片)
基於當前屏幕的密度,android平臺會從應用程序自動加載指定大小,與密度的資源(均未縮放),如果沒有適配的資源可用,平臺將加載默認文件夾下的資源(即drawable文件夾中的資源)並根據需要縮小或放大資源以適配當前屏幕的一般屏幕密度。除非資源被加載到指定密度目錄下,一般情況平臺加載的默認資源是展現效果最好的,展現在基於最基本密度爲"medium" (160)的屏幕上。
例如:如果當前屏幕的密度爲高密度(high),平臺將加載drawable-hdpi文件夾下的資源,使用時並不縮放圖片大小。如果drawable-hdpi中無資源可用,或無此文件夾,平臺將加載默認資源即drawable文件裏的資源,並且放大圖片大小,從基本密度到最大密度。
2、自動縮放像素維值與座標
如果應用程序不支持多屏幕,平臺將自動縮放任何絕對像素座標,像素維值,像素數學。平臺如此做是爲確保像素定義的屏幕元素更接近屏幕物理尺寸呈現,像它們在最基本密度160上表現的一樣。平臺對於應用程序的縮放很明顯,並且會認爲應用程序屏幕大小爲縮放後的像素維值而不是物理像素維值
例如:假定用一個WVGA的高密度屏幕,480*800,相當於傳統HVGA的屏幕大小,但是運行一個不支持多屏幕的應用程序。在這種情況下,系統在獲取屏幕大小時,會誤認爲是320*533。然後,會使從座標(10,10)到座標(100,100)的長方形失效,系統將自動縮放座標到合適大小,即從(15,15)到(150,150)。這種情況也會發生在其它地方,如果應用程序運行在低密度的屏幕上,座標也會被縮小
3、在大屏幕上的兼容模式
1.Screen size 屏幕實際尺寸。
Android講屏幕實際尺寸分爲3個通用的尺寸。
2.Aspect ratio 長寬比
3.Resolution 分辨率
4.Density 密度
5.Density-independent pixel 密度無關的像素
介紹:Adnroid1.6或以上SDK,在AndroidManifest.xml中提供新的一個元素<supports-screens>用於支持多屏幕機制。
<supports-screens
android:largeScreens="true" 是否支持大屏
android:normalScreens="true" 是否支持中屏
android:smallScreens="true" 是否支持小屏
android:anyDensity="true" 是否支持多種不同密度
/>
Android提供3種方式處理屏幕自適應
一.預縮放的資源(基於尺寸和密度去尋找圖片)
1.如果找到相應的尺寸和密度,則利用這些圖片進行無縮放小時。
2.如果沒法找到相應的尺寸,而找到密度,則認爲該圖片尺寸爲 "medium",利用縮放這個圖片顯示。
3.如果都無法匹配,則使用默認圖片進行縮放顯示。默認圖片默認標配 "medium" (160)。
二.自動縮放的像素尺寸和座標(密度兼容)
1.如果應用程序不支持不同密度android:anyDensity="false",系統自動縮放圖片尺寸和這個圖片的座標。
(代碼中體現)
2.對於預縮放的資源,當android:anyDensity="false",也不生效。
3.android:anyDensity="false",只對密度兼容起作用,尺寸兼容沒效果
三.兼容模式顯示在大屏幕,尺寸(尺寸兼容)
1.對於你在<supports-screens>聲明不支持的大屏幕,而這個屏幕尺寸是normal的話,系統使用尺寸爲 ("normal")和密度爲("medium)顯示。
2.對於你在<supports-screens>聲明不支持的大屏幕,而這個屏幕尺寸是larger的話,系統同樣使用尺寸爲 ("normal")和密度爲("medium)顯示,不過會出現一層黑色的背景。不是居中顯示。
密度獨立:
系統默認應用支持DIP單位的,三個使用DIP的地方:
1.加載資源時,使用DIP實現預縮放的資源。
2.在Layout使用DIP,系統自動完成縮放。
3.在應用程序中,自動縮放一些絕對像素。
(只有在android:anyDensity="false"生效)即屏幕自適應方式二
4.像素單位都使用DIP,文本單位使用SP
最佳屏幕獨立實踐:
1.使用wrap_content, fill_parent 和使用dip作爲像素單位in XML layout files。
2.避免使用AbsoluteLayout
3.在代碼中,不要使用像素數字硬編碼,而是要通過dip轉換爲px。
例子:
你使用手勢分析器分析一個scroll手勢,假如,你滾動的距離是16px。
1.在一個160dip的屏幕中,你實際移動距離 16px / 160dpi = 1/10th of an inch (or 2.5 mm)
2.在一個240dip的屏幕中,你實際移動距離 16px / 240dpi = 1/15th of an inch (or 1.7 mm)
// The gesture threshold expressed in dip
private static final float GESTURE_THRESHOLD_DIP = 16.0f;
// Convert the dips to pixels
final float scale = getContext().getResources().getDisplayMetrics().density;
mGestureThreshold = (int) (GESTURE_THRESHOLD_DIP * scale);
4.使用密度和/或尺寸特定資源(通過文件夾)
關於預縮放或者自動縮放圖片或9格圖
1.系統是一定對會資源包下的圖片進行合理的縮放。
例如:一張240x240高密度圖片,顯示在中密度的屏幕上,圖片大小自動變爲160x160。
2.你在API中不會得到被縮放後的圖片尺寸,得到還是你原來圖片的尺寸。
3.如果你不想系統自動幫你縮放圖片,可以建立一個res/drawable-nodpi文件夾,存放你的圖片。
4.也可以通過BitmapFactory.Options 完成系統自動縮放圖片或9格圖(在畫圖時)。
5.自動縮放圖片比預縮放花費更多CPU,但是用更少內存(RAM or ROM ?)
Android : dip/dp與px(pixel)之間的相互轉換
Author : Aoyousatuo Zhao
http://blog.sina.com.cn/aoyousatuo
在Android應用的開發過程中,我們常常需要給組件佈局定位。這就涉及到Android常用的兩個計量單位dip/dp, px.下面筆者就這兩個單位做一個簡要的介紹。
dip或者dp是device independent pixels(設備獨立像素)的縮寫。這個單位提出的目的主要是爲了讓應用的UI佈局適應各種分辨率的顯示設備。Android會將dp最終轉換成具體顯示設備的像素數,這樣就提高了程序的可移植性。
px是pixel的縮寫,它表示一個實實在在的物理像素。這個單位使用起來比較方便,但是組件一旦定位就固定了,它不會隨着設備的分辨率不同而改變,使用該單位的程序可移植性較差。
舉個例子,在400像素寬的屏幕上從第0個像素到第399個像素畫一條橫線,我們可以看到這條線橫向貫穿了整個屏幕,然後我們將相同的畫線程序運行在800像素寬的屏幕上,則我們只能看到這條線只有屏幕的一半。如果換作dp爲單位,則在這兩種分辨率的屏幕上的線基本都橫向貫通。
所以在開發中,爲了提高程序對各種設備的適應性,我們最好使用dp或者dip爲單位。知道了這兩個單位的特點,問題就來了。我們發現雖然一些組件可以在佈局文件中通過dip或者dp單位來定構。但是,組件類的相關方法卻只能以像素爲單位。例如,設置GridView組件類的列間距。這種情況下就涉及到了dip/dp與px之間的相互轉換。筆者直接給出兩個方法大家就清楚了,請看:
public int dip2px(Context context, floatdipValue)
{
floatm=context.getResources().getDisplayMetrics().density ;
return (int)(dipValue * m + 0.5f) ;
}
public int px2dip(Context context, floatpxValue)
{
}
面對Android設備那混亂的硬件體系,最淡定的開發者也會不免蛋疼起來。在做Android UI的時候,考慮最多的就是這些不同設備的適配問題。在爲不同分辨率設計不同UI的時候,我們首先要知道目標設備的分辨率到底是多少。如何計算出來?
水果手機經常喜歡用分辨率超過人眼極限來標榜自己的設備有多麼牛B,據說iPhone 4S的分辨率達到了326 PPI(pixel per inch),這個數值的計算公式爲:
開方(屏幕寬度平方+屏幕高度平方)÷對角線尺寸
iPhone 4S,960×640像素,對角線尺寸3.5英寸,用上面的公式計算結果如下:
sqrt(sqr(960) + sqr(640)) / 3.5 ≈ 329.65
看來水果公司並未說謊。只是3.5寸的屏搞這麼高的分辨率,考視力麼?
和水果比起來,Android就更加複雜了,它把屏幕分成small,normal,large,xlarge四種,其對應的屏幕尺寸如下:
- xlarge 至少960dp x 720dp
- large 至少640dp x 480dp
- normal 至少470dp x 320dp
- small 至少426dp x 320dp
dp(Density-independent pixel)是一個密度無關的像素單位,是用來表示基於160 dpi的設備計算出來的虛擬像素。
屏幕分辨率被分成low dpi,medium dpi,high dpi,extra high dpi。詳見下圖:
最近的Android設備屏幕分佈圖: