开发语言android的密度,dpi.dip等解释!!!!!

本文详细解析了Android系统的屏幕适配原理,包括不同分辨率和密度的处理方式、UI设计注意事项及资源文件配置策略。

原文:http://www.01yun.com/web/20130112/72066.html

 

android的密度,dpi.dip等解释!!!!!

1.术语和概念

指的是手机实际的物理尺寸,比如常用的2.8英寸,3.2英寸,3.5英寸,3.7英寸(对角线长度)

每英寸像素数,如120dpi,160dpi等,假设QVGA(320*240)分辨率的屏幕物理尺寸是(2英寸*1.5英寸),dpi=160 所以dpi = 分辨率的高宽的平方根(对角线)除以物理尺寸高宽的平方根(对角线).

屏幕里像素值浓度,resolution/Screen size可以反映出手机密度,    (dpi/160)

指的是逻辑密度计算单位,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所示:

WQVGA400 (240x400)WQVGA432 (240x432)

WVGA800 (480x800)WVGA854 (480x854)

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

Standard Asset Sizes (in Pixels), for Generalized Screen Densities

表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是从Android2.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 获取屏幕尺寸与密度:

android中获取屏幕的长于宽,参考了网上有很多代码,但结果与实际不符,如我的手机是i9000,屏幕大小是480*800px,得到的结果却为320*533

结果很不靠谱,于是自己写了几行代码,亲测一下

测试参数:

测试环境: i9000(三星)

物理屏幕:480*800px

density :1.5

测试代码:

Java代码 

// 获取屏幕密度(方法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);  

结果如下:

Java代码 

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之间,例如

但是,这就说明方法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.

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值