Android平板上开发应用的一点心得——精确适配不同的dpi和屏幕尺寸
一、引言
Android的开源使厂商无需自行研发OS,大大降低了研发、生产的成本,使得Android平板品牌如雨后春笋般爆发,山寨机厂商们似乎又找到了一丝希望。与此同时带来的是广大开发者的苦不堪言,各种神奇的小板儿考验着app的兼容性,各种定制的rom不经意间就让app崩溃,光是界面上的调整就已经够你喝一壶了,是不?
二、适配可行性
早在Android设计之初就考虑到了这一点,为了让app适应标准or山寨屏幕,google已经有一套成熟的解决方案。其中,有这么几个指标需要注意:
(1)屏幕尺寸:单位inch,指的是屏幕对角线长度。
(2)屏幕密度:单位dpi,指的是每inch上可以显示多少像素点即px。
(3)屏幕分辨率:单位px * px,指的是一屏显示多少像素点。
(4)屏幕无关像素:单位dp/dip,指的是自适应屏幕密度的像素,用于指定控件宽高。
(5)刻度无关像素:单位sp,指的是自适应字体的像素,用于指定文字大小。
以我自己的Haier W910超级战舰(宽高比16:9)为例,上述单位的换算如下:
已知数据:屏幕尺寸4.5, 分辨率1280 * 720, 屏幕密度320
(1)16:9的4.5寸屏幕由勾股定理计算其高约为3.9寸,宽约为2.2寸
(2)则竖向dpi为1280 / 3.9 ≈ 328, 横向dpi为720 / 2.2 ≈ 327
(3)工业上切割液晶板时取整为320
那么既然dpi是自适应屏幕密度的,与px之间又是如何换算呢:
120dpi(ldpi低密度屏) 1dp = 0.75px (由于像素点是物理点,所以用2个像素点来显示3个dp的内容)
160dpi(mdpi中密度屏) 1dp = 1px
213dpi(tvdpi电视密度屏) 1dp = 1.33px
240dpi(hdpi高密度屏) 1dp = 1.5px
320dpi(xhdpi极高密度屏) 1dp = 2px
由上述分析结果可知,控件使用dp,文字使用sp即可满足自适应的需求。
三、适配方案
根据目前的调查,在市面上的平板,基本上属于mdpi和hdpi的,少数属于tvdpi(如google出的nexus7),所以我们选择这三种密度考虑适配;此外手机应用大多数都是竖屏使用,但平板作为娱乐性的一款产品,横竖屏均有使用的时候,所以我们还需要考虑到屏幕状态进行适配;最后考虑到有的rom会将虚拟键计算到屏幕尺寸里,还要考虑到虚拟键所占用的长宽。
那么如何根据这三个属性来进行适配呢?Android在资源文件values用文件名的方式提供了限定符可以帮助我们判断上述情况,限定符(mdpi,tvdpi,hdpi)可以帮助我们判断屏幕密度,限定符(land,port)可以帮助我们区分屏幕横竖屏状态,而限定符(1024x600...)可以适配计算虚拟键或者不计算虚拟键的屏幕,限定符的详细说明请参见Android SDK文档中开发者指南的Supporting Multiple Screens话题。
最终适配文件夹如下图所示:
注1:分辨率限定符的匹配是向下匹配,如果没有values-land-mdpi-1024x552,比如,分辨率values-land-mdpi-1024x600的屏幕,当rom不把虚拟键计算到屏幕尺寸时,实际显示的屏幕应该是values-land-mdpi-1024x552,无法适配到values-land-mdpi-1024x600,那这样就可能适配到下一级,比如values-land-mdpi-800x480,但是现在的平板已经没有这么低的分辨率了,所以是配到无限定符的values-mdpi里,造成界面显示上的瑕疵。
注2:由于分辨率限定符的匹配是向下匹配,所以如果有非主流mdpi屏幕不能精确适配到上述指定值时,values-mdpi至少可以保证app运行时不至于崩溃,同理values可以保证ldpi屏幕的平板不会因生成view而又取不到相应值而崩溃。
android屏幕适配小结
分类: 记录点滴2012-07-22 15:28 3307人阅读 评论(11) 收藏 举报
做android开发,开源嘛,满市场都是凌乱的机型,总少不了适配这样或那样的型号。在这里分享一下自己在开发中用到的方法。
首先要介绍一下drawable-mdpi、drawable-hdpi-1280x800、drawable-hdpi。这个相信好好看一下也明白。就是代表着分辨率320X480、1280X800、480X800三款屏幕图片资源包。其实适配也很多。我大致说一种就行,其他大家慢慢琢磨,或上网周转。
说明一下这个图的意思,就是我要说的配置方法,就是一套图片资源(资源文件要看美工的设计了。最好能是XXX.9.png)配一套布局文件及多套数值文件。
布局文件:
[html] view plaincopyprint?
1. <?xml version="1.0" encoding="utf-8"?>
2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3. android:layout_width="fill_parent"
4. android:layout_height="fill_parent"
5. android:orientation="vertical" >
6.
7. <ImageView
8. android:layout_width="@dimen/imagewidth"
9. android:layout_height="wrap_content"
10. android:background="@drawable/ic_launcher" />
11.
12. </LinearLayout>
数值文件:
[html] view plaincopyprint?
1. <?xml version="1.0" encoding="utf-8"?>
2. <resources>
3. <!-- values-hdpi 480X800 -->
4. <dimen name="imagewidth">320dip</dimen>
5. </resources>
[html] view plaincopyprint?
1. <resources>
2. <!-- values-hdpi-1280x800 -->
3. <dimen name="imagewidth">320dip</dimen>
4. </resources>
[html] view plaincopyprint?
1. <?xml version="1.0" encoding="utf-8"?>
2. <resources>
3. <!-- values-hdpi 480X320 -->
4. <dimen name="imagewidth">320dip</dimen>
5. </resources>
Android上常见度量单位【xdpi、hdpi、mdpi、ldpi】解读
术语和概念
屏幕尺寸
屏幕的物理尺寸,以屏幕的对角线长度作为依据(比如 2.8寸, 3.5寸)。
简而言之, Android把所有的屏幕尺寸简化为三大类:大,正常,和小。
程序可以针对这三种尺寸的屏幕提供三种不同的布局方案,然后系统会负责把你的布局方案以合适的方式渲染到对应的屏幕上,这个过程是不需要程序员用代码来干预的。
屏幕长宽比
屏幕的物理长度与物理宽度的比例。程序可以为制定长宽比的屏幕提供制定的素材,只需要用系统提供的资源分类符long和 notlong。
分辨率
屏幕上拥有的像素的总数。注意,虽然大部分情况下分辨率都被表示为“宽度×长度”,但分辨率并不意味着屏幕长宽比。在 Android系统中,程序一般并不直接处理分辨率。
密度
以屏幕分辨率为基础,沿屏幕长宽方向排列的像素。
密度较低的屏幕,在长和宽方向都只有比较少的像素,而高密度的屏幕通常则会有很多 ——甚至会非常非常多——像素排列在同一区域。屏幕的密度是非常重要的,举个例子,长宽以像素为单位定义的界面元素(比如一个按钮),在低密度的屏幕上会 显得很大,但在高密度的屏幕上则会显得很小。
密度无关的像素( DIP)
指一个抽象意义上的像素,程序用它来定义界面元素。它作为一个与实际密度无关的单位,帮助程序员构建一个布局方案(界面元素的宽度,高度,位置)。
一个与密度无关的像素,在逻辑尺寸上,与一个位于像素密度为 160DPI的屏幕上的像素是一致的,这也是Android平台所假定的默认显示设备。在运行的时候,平台会以目标屏幕的密度作为基准,“透明地”处理所 有需要的DIP缩放操作。要把密度无关像素转换为屏幕像素,可以用这样一个简单的公式: pixels = dips * (density/ 160)。举个例子,在DPI为240的屏幕上,1个 DIP等于 1.5个物理像素。我们强烈推荐你用 DIP来定义你程序的界面布局,因为这样可以保证你的 UI在各种分辨率的屏幕上都可以正常显示。
为了简化程序员面在对各种分辨率时的困扰,也为了具备各种分辨率的平台都可以直接运行这些程序,Android平台将所有的屏幕以密度和分辨率为分类方式,各自分成了三类:
·三种主要的尺寸:大,正常,小;
·三种不同的密度:高(hdpi),中(mdpi)和低(ldpi)。 【DPI是“dot perinch”的缩写,每英寸像素数。】
如果需要的话,程序可以为各种尺寸的屏幕提供不同的资源(主要是布局),也可以为 各种密度的屏幕提供不同的资源(主要是位图)。除此以外,程序不需要针对屏幕的尺寸或者密度作出任何额外的处理。在执行的时候,平台会根据屏幕本身的尺寸 与密度特性,自动载入对应的资源,并把它们从逻辑像素(DIP,用于定义界面布局)转换成屏幕上的物理像素。
关于Android的nodpi,xhdpi,hdpi,mdpi,ldpi
首先是几个基本概念:
1.屏幕尺寸Screen size
即显示屏幕的实际大小,按照屏幕的对角线进行测量。
为简单起见,Android把所有的屏幕大小分为四种尺寸:小,普通,大,超大(分别对应:small,normal, large, and extra large).
应用程序可以为这四种尺寸分别提供不同的自定义屏幕布局-平台将根据屏幕实际尺寸选择对应布局进行渲染,这种选择对于程序侧是透明的。
2.屏幕长宽比Aspect ratio
长宽比是屏幕的物理宽度与物理高度的比例关系。应用程序可以通过使用限定的资源来为指定的长宽比提供屏幕布局资源。
3.屏幕分辨率Resolution
在屏幕上显示的物理像素总和。需要注意的是:尽管分辨率通常用宽x高表示,但分辨率并不意味着具体的屏幕长宽比。
在Andorid系统中,应用程序不直接使用分辨率。
4.密度Density
根据像素分辨率,在屏幕指定物理宽高范围内能显示的像素数量。
在同样的宽高区域,低密度的显示屏能显示的像素较少,而高密度的显示屏则能显示更多的像素。
屏幕密度非常重要,因为其它条件不变的情况下,一共宽高固定的UI组件(比如一个按钮)在在低密度的显示屏上显得很大, 而在高密度显示屏上看起来就很小。
为简单起见,Android把所有的屏幕分辨率也分为四种尺寸:小,普通,大,超大(分别对应:small,normal, large, and extra large).
应用程序可以为这四种尺寸分别提供不同的资源-平台将透明的对资源进行缩放以适配指定的屏幕分辨率。
5.设备独立像素Density-independent pixel (dp)
应用程序可以用来定义UI组件的虚拟像素单元,通过密度无关的方式来描述布局尺寸和位置。
一个设备独立像素相当于一个160 dpi屏幕上的物理像素。
在程序运行时,系统根据屏幕的实际密度透明的处理任何需要缩放的设备独立像素单元,设备独立像素转换成屏幕实际像素的换算很简单:pixels =dps * (density / 160).
例如在240 dpi的屏幕上,1个设备独立像素等于1.5物理像素.为确保UI组件在不同的屏幕都能合适的展示,强烈建议使用设备独立像素单元来定义你的应用程序UI。
四种屏幕尺寸分类::small, normal, large, and xlarge
四种密度分类: ldpi(low), mdpi (medium), hdpi (high), and xhdpi (extra high)
需要注意的是: xhdpi是从 Android 2.2 (APILevel 8)才开始增加的分类.
xlarge是从Android 2.3 (APILevel 9)才开始增加的分类.
DPI是“dot per inch”的缩写,每英寸像素数。
一般情况下的普通屏幕:ldpi是120,mdpi是160,hdpi是240,xhdpi是320。
参考:http://developer.android.com/images/screens_support/screens-ranges.png
两种获取屏幕分辨率信息的方法:
DisplayMetrics metrics = new DisplayMetrics();
Display display = activity.getWindowManager().getDefaultDisplay();
display.getMetrics(metrics);
//这里得到的像素值是设备独立像素dp
//DisplayMetricsmetrics=activity.getResources().getDisplayMetrics(); 这样获得的参数信息不正确,不要使用这种方式。
不能使用android.content.res.Resources.getSystem().getDisplayMetrics()。这个得到的宽和高是空的。
private
voidinitResolutionStr(Context context) {
if(ApiConfig.getResolutionStr() ==
null ||ApiConfig.getResolutionStr().equals("")) {
WindowManager winMgr =(WindowManager)context.getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
Display display =winMgr.getDefaultDisplay();
intheight = display.getHeight();
int width= display.getWidth();
String resolution = height> width ? height + "x" + width : width + "x" + height;
ApiConfig.setResolutionStr(resolution);
// densityDpi =120dpi is ldpi, densityDpi = 160dpi is mdpi,
// densityDpi = 240dpi ishdpi, densityDpi = 320dpi is xhdpi
DisplayMetricsdm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
intdensityDpi = dm.densityDpi;
ApiConfig.setDensityDpi(densityDpi);
}
}
如果需要为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上常见度量单位:
px(像素):屏幕上的点,绝对长度,与硬件相关。
in(英寸):长度单位。
mm(毫米):长度单位。
pt(磅):1/72英寸,point。
dp(与密度无关的像素):一种基于屏幕密度的抽象单位。在每英寸160点的显示器上,1dp = 1px。
dip:Density-independent pixel,同dp相同。
sp:在dp的基础上,还与比例无关,个人理解为是一个矢量图形单位。
引入dp/dip的原因:
过去,程序员通常以像素为单位设计计算机用户界面。例如,定义一个宽度为300像素的表单字段,列之间的间距为5个像素,图标大小为16×16像素等。这样处理的问题在于,如果在一个每英寸点数(dpi)更高的新显示器上运行该程序,则用户界面会显得很小。在有些情况下,用户界面可能会小到难以看清内容。与分辨率无关的度量单位可以解决这一问题。
如何计算密度(请参照原帖:http://www.devdiv.com/thread-28610-1-1.html);
1.标准是240*320画在1.5*2平方inch上。那么像每平方英寸有240*320/(1.5*2)=25600点,也就是一平方英寸的像素点为25600,所以dpi取为它的平方根160;如果你的dpi是120,那么它的密度就是0.75.
2.密度不只是与width有关,还与height有关,所以不管width是1.8还是1.3,它的密度都有可能是1;比如width是1.8,只要它的height是3/1.8的话,如果pixel为240*320的话,它的密度仍旧是1;同样如果width为1.3,只要它的
height为3/1.3的话,像素点为240*320,则密度也是1.
3.320*480/(1.5*2)得到单位平方英寸的点为51200,所以单位平方英寸是240*320画在1.5*2屏幕的2倍。但是这是平方英寸啊,算密度的时候要开平方的啊,所以应该是2开平方,是1.414吧,大致密度为1.5。
如何做到与密度无关:
如果屏幕密度为160,这时dp和sp和px是一样的。1dp=1sp=1px,但如果使用px作单位,如果屏幕大小不变(假设还是3.2寸),而屏幕密度变成了320。那么原来TextView的宽度设成160px,在密度为320的3.2寸屏幕里看要比在密度为160的3.2寸屏幕上看短了一半。但如果设置成160dp或160sp的话。系统会自动将width属性值设置成320px的。也就是160
* 320 /160。其中320 / 160可称为密度比例因子。也就是说,如果使用dp和sp,系统会根据屏幕密度的变化自动进行转换。官方文档总结的计算公式为:pixels
=dps * (density /160).
附:
传说iPhone/Mac的设计从一开始就考虑到对任意分辨率的支持,iOS的所有介面元素用的都已经是矢量化了的图片,UI界面是系统级别的与密度无关;而Android虽然支持任意分辨率,但不是系统全局的,求证。
s
支持不同的屏幕尺寸
这部分内容向你展示了如何支持不同的屏幕尺寸:
·确保你的布局可以充分调整大小以适合屏幕
·提根据屏幕配置供适当的UI布局layout文件
·确保正确的布局layout用于正确的屏幕
·提供Bitmaps可以争取的缩放
1 使用 "wrap_content"和 "match_parent"属性进行配置、
在对有些布局组件的高度和宽度进行设置时尽量使用"wrap_content"和"match_parent"属性。如果使用 wrap_content,组件的高度和宽度被设置为需要适合组件中内容的最小尺寸。而match_content 属性使得组件扩展到适合父组件布局的大小。
但是使用"wrap_content"和 "match_parent"属性替代硬尺寸编码,你的组件布局要嘛只是控件需要的大小,要嘛就是扩展到填充父组件中所有可用的空间。
2 使用相对布局RelativeLayout
你可以构建相当复杂的布局通过使用LinearLayout和"wrap_content"和 "match_parent"的结合。但是LinearLayout不允许你精确控制子组件布局之间的精确关系。LinearLayout布局中的组件只是线性的一个挨着一个。如果需要子控件被确定为各种各样的位置,而不是仅仅是个直线状态,比较好的方法就是使用RelativeLayout,这样你就能明确的指定不同组件之间的位置关系。
Android屏幕尺寸适配注意事项
作者:皇马船长更新于 04月09日访问(271)评论(0)
1 基本设置
1.1AndroidManifest.xml设置
在中添加子元素
android:anyDensity="true"时,应用程序安装在不同密度的终端上时,程序会分别加载xxhdpi、xhdpi、hdpi、mdpi、ldpi文件夹中的资源。 相反,如果设为false,即使在文件夹下拥有相同资源,应用不会自动地去相应文件夹下寻找资源:
1)如果drawable-hdpi、drawable-mdpi、drawable-ldpi三个文件夹中有同一张图片资源的不同密度表示,那么系统会去加载drawable_mdpi文件夹中的资源;
2)如果drawable-hpdi中有高密度图片,其它两个文件夹中没有对应图片资源,那么系统会去加载drawable-hdpi中的资源,其他同理;
3)如果drawable-hdpi,drawable-mdpi中有图片资源,drawable-ldpi中没有,系统会加载drawable-mdpi中的资源,其他同理,使用最接近的密度级别。
1.2 横屏竖屏目录区分
1)drawable
a)drawable-hdpi该图片即适用于横屏,也适用于竖屏;
b)drawable-land-hdpi,当屏幕为横屏,且为高密度时,加载此文件夹的资源;
c)drawable-port-hdpi,当屏幕为竖屏,且为高密度时,加载此文件夹中的资源。其他同理。
2)layout
在res目录下建立layout-port和layout-land两个目录,里面分别放置竖屏和横屏两种布局文件,以适应对横屏竖屏自动切换。
2 多屏幕适配的4条黄金原则
1)在layout文件中设置控件尺寸时应采用fill_parent、wrap_content、match_parent和dp;
具体来说,设置view的属性android:layout_width和android:layout_height的值时,wrap_content,match_parent或dp比px更好,文字大小应该使用sp来定义。
2)在程序的代码中不要出现具体的像素值,在dimens.xml中定义;
为了使代码简单,android内部使用pix为单位表示控件的尺寸,但这是基于当前屏幕基础上的。为了适应多种屏幕,android建议开发者不要使用具体的像素来表示控件尺寸。
3)不使用AbsoluteLayout(android1.5已废弃) ,可以使用RelativeLayout替代;
4)对不同的屏幕提供合适大小的图片。
不同大小屏幕用不同大小的图片,low:medium:high:extra-high图片大小的比例为3:4:6:8;举例来说,对于中等密度(medium)的屏幕你的图片像素大小为48×48,那么低密度(low)屏幕的图片大小应为36×36,高(high)的为72×72,extra-high为96×96。
3 使用9-patch PNG图片
使用图片资源时,如果出现拉伸,因为图片处理的原因,会变形,导致界面走形。9-patch PNG图片也是一种标准的PGN图片,在原生PNG图片四周空出一个像素间隔,用来标识PNG图片中哪些部分可以拉伸、哪些不可以拉伸、背景上的边框位置等。
“上、左”定义可拉伸区域
“右、下”定义显示区域,如果用到完整填充的背景图,建议不要通过android:padding来设置边距,而是通过9-patch方式来定义。
Android SDK中提供了编辑9-Patch图片的工具,在tools目录下draw9patch.bat,能够立刻看到编辑后的拉伸效果,也可以直接用其他图片编辑工具编辑,但是看不到效果。
4不同的layout‘
Android手机屏幕大小不一,有480x320, 640x360, 800x480.怎样才能让Application自动适应不同的屏幕呢?
其实很简单,只需要在res目录下创建不同的layout文件夹,比如layout-640x360,layout-800x480,所有的layout文件在编译之后都会写入R.java里,而系统会根据屏幕的大小自己选择合适的layout进行使用。
5 测试验证
一般使用AVD Manager创建多个不同大小的模拟器,
来源:CSDN
作者:军军1006
链接:https://blog.csdn.net/caijunjun1006/article/details/9924359