Android开发中的density
ComptibilityInfo.java
http://www.tuicool.com/articles/ZZZRNf
andorid界面单位开发是应该是dip
自适应,包括元素大小自适应,和位置自适应。
元素大小:
图片默认会自适应的。
dip会自适应。
自适应问题。一个公式 px=dip*(density/160);(density/160)在android系统中对应 DisplayMetrics.density在一固定的手机上它是一个常数,0.75,1,1.5。等。有了这个常数用dip做单位在不同手机上就有不同的px了。这就是缩放原理。
drawable-hdpi、drawable-mdpi、drawable-ldpi中的图片是自动选择的。但是如果对应的文件夹下没有所需的图片它会在其他两个文件夹下寻找,找到了按density缩放。
元素坐标:
图片坐标,和触屏事件坐标。 都用相对坐标 。
自适应原则:图片缩放自适应,位置用相对位置(单位也用dip)。
所有的机型宽都是相等的dip数,高不一定是相等的dip数。
240x320 density=120 320dipx426.6dip
320x480 density=160 320dipx480dip
480x800 density=240 320dipx533.3dip
480x854 density=240 320dipx569.33dip
我感觉,做手机的屏幕自适应比做web的浏览器兼容更麻烦..以下是搜到的资料,原来android还有这些不为人知的东西: 一:不同的layout Android手机屏幕大小不一,有480x320, 640x360, 800x480.怎样才能让App自动适应不同的屏幕呢? 其实很简单,只需要在res目录下创建不同的layout文件夹,比如layout-640x360,layout-800x480,所有的layout文件在编译之后都会写入R.java里,而系统会根据屏幕的大小自己选择合适的layout进行使用。 二:hdpi、mdpi、ldpi 在之前的版本中,只有一个drawable,而2.1版本中有drawable-mdpi、drawable-ldpi、drawable-hdpi三个,这三个主要是为了支持多分辨率。 drawable- hdpi、drawable- mdpi、drawable-ldpi的区别: (1)drawable-hdpi里面存放高分辨率的图片,如WVGA (480x800),FWVGA (480x854) (2)drawable-mdpi里面存放中等分辨率的图片,如HVGA (320x480) (3)drawable-ldpi里面存放低分辨率的图片,如QVGA (240x320) 系统会根据机器的分辨率来分别到这几个文件夹里面去找对应的图片。 在开发程序时为了兼容不同平台不同屏幕,建议各自文件夹根据需求均存放不同版本图片。
![](http://img0.tuicool.com/RzAZZ3.jpg)
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 |
可以反映屏幕的清晰度,用于缩放UI的 |
Density(密度) |
屏幕里像素值浓度,resolution/Screen size可以反映出手机密度, |
|
Density-independent pixel (dip) |
指的是逻辑密度计算单位,dip和具体像素值的对应公式是dip/pixel=dpi值/160,也就是 px = dp * (dpi / 160) |
|
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有个自动匹配机制去选择对应的布局和图片资源
今天一个开发者问到我为什么游戏开发要删除项目下的hdpi、mdpi和ldpi文件夹;下面详细给大家解答一下:
首先童鞋们如果看过我写的《 【Android游戏开发二十一】Android os设备谎言分辨率的解决方案! 》这一节的话都应该知道Android从1.6和更高,Google为了方便开发者对于各种分辨率机型的移植而增加了自动适配的功能;
自动适配的原理很简单,只要你建立的项目是1.6或者更高都会看到项目下有drawable-hdpi、drawable-mdpi、drawable-ldpi 三个文件夹,这三个文件夹分别放置高清分辨率、中分辨率、低分辨率的资源文件;那么如果你的项目在高清分辨率上运行的话,系统会默认索引drawable-hdpi文件夹下的资源,其他雷同;
那么既然系统会自动找匹配的文件夹,那么肯定会出现找不到的情况,比如当前你的应用在高清分辨率运行,假设代码中加载一张“himi.png”的图,那么系统首先会去drawable-hdpi文件夹下去找这张图,一旦找不到,系统会再到其他drawable下寻找,再假设你其实把这张“himi.png”放在了drawable-mdpi中,那么系统会默认把这张图片放大;反之一样,如果你在低分辨率中运行加载一张图片的话,一旦你将图片放入高清的drawable-dpi中,那么系统默认缩小这张图;
总结来说:如果你的应用想适配高、中、低分辨率,那么你需要有3套图放入对应的文件夹中,这样系统会智能加载;如果你就想保留一个文件夹,不想让系统智能寻找缩放的话,有两种方式可以解决:
1.删除drawable-hdpi、drawable-mdpi、drawable-ldpi三个文件夹,创建一个drawable文件夹即可;
2.将资源文件放入assets中,因为assets中的资源系统永远不会为其生成id,所以不会智能缩放;
-------------------下面介绍第二点,如何让你的游戏应用高清
其实还是在《 【Android游戏开发二十一】Android os设备谎言分辨率的解决方案! 》中介绍过,1.6后android有了智能判断的缘故,你获取的屏幕宽高其实是不准确的,详情可以参考 【Android游戏开发二十一】Android os设备谎言分辨率的解决方案! 》;那么这里要补充一点就是:
如果你在AndroidMainFest 中,定义 <uses-sdk android:minSdkVersion="4" /> 就OK了!你会发现你的图片很清楚,其实也是因为android自动缩放造成的,上面说了,一般获取的分辨率会不正常(比正确的偏小)那么一旦你加上这一句之后,你的分辨率就正常了,所以就明显游戏质量高了一个档次。
这里再补充一下: 一旦你定义了<uses-sdk android:minSdkVersion="4" />,就是限制1.5SDK的手机无法安装你的程序;
OK,继续忙了,大家尝试下吧~
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 ?)
一、相关概念
a) android支持density的版本 Android从1.6版本开始支持density(对应API Level 4)
b) density density值表示每英寸有多少个显示点,比如240就是每英寸240个点,它是针对设备的属性,它是屏幕物理长宽的扩展,给屏幕设置为低密度显示的内容少,同样的条件下,密度小的屏幕显示同样的按钮看起来大,高密度的看起来小
c) 分辨率 是整个屏是多少点,比如800x480,它是对于软件来说的显示单位,以px为单位的点
d) 设置density的效果 不同density下屏幕分辨率信息,以480dip*800dip的WVGA为例 density=120时 屏幕实际分辨率为240px*400px density=160时 屏幕实际分辨率为320px*533px density=240时 屏幕实际分辨率为480px*800px
二、相关代码及设置
a) AndroidManifest.xml <supports-screens android:anyDensity="true"/> <uses-sdk android:minSdkVersion="4"></uses-sdk>
b) 资源目录名(android 2.0以后) res/xxx-hdpi 当density为240时,使用此目录下的资源 res/xxx-mdpi 当density为160时,使用此目录下的资源 res/xxx-ldpi 当density为120时,使用此目录下的资源 res/xxx 不常后缀,为默认设置,同xxx-mdpi 如果硬件相应的desity的目录不存在,系统会利用存在的density自动乘以系数计算出相应的density
c) 资源单位(layout xml文件中定义大小的单位)
i. dp=dip=dx ( Density independent pixel ) 基于屏幕密度的抽象单位,布局时尽量使用单位dip,少使用px dip是 应用用于定义UI的虚拟单位,用于说明与密度无关的尺寸和位置。 dip点等价于160dpi密度中的一个物理点,密度由平台决定,换算公式如下 pixels = dips * (density / 160)
,
160DPI的密度系数是1
例如 240 dpi的屏幕,1个dip点等于1.5个物理点
ii. px 设置的绝对点数, 如果使用更高density的系统, 控件就会变小
三、设置density 设置系统变量hw.lcd.density,可设置density
四、实现density的关键源码
a) BitmapFactory.java
b) ComptibilityInfo.java