如何将一个应用程序适配在不同的手机上,虽然这不算是一个技术问题,但是对于刚刚做屏幕的开发人员来说,还真不是一件多么简单的事情。
首先:你需要在AndroidManifest.xml文件的<manifest>元素如下添加子元素
<supports-screens android:largeScreens="true"
android:normalScreens="true" android:anyDensity="true"
android:smallScreens="true"></supports-screens>
名如其意,以上是为我们的屏幕设置多分辨率支持(更准确的说是适配大、中、小三种密度)。android:anyDensity="true" ,这一句对整个的屏幕都起着十分重要的作用,值为true,我们的应用程序当安装在不同密度的手机上时,程序会分别加载hdpi,mdpi,ldpi文件夹中的资源。
相反,如果值设置为false,即使我们在hdpi,mdpi,ldpi文件夹下拥有同一种资源,那么应用也不会自动地去相应文件夹下寻找资源,这种情况都是出现在高密度,以及低密度的手机上,比如说一部240×320像素的手机,如果设置android:anyDensity="false",Android系统会将240 x 320(低密度)转换为 320×480(中密度),这样的话,应用就会在小密度手机上加载mdpi文件中的资源。
2.细心的人会发现自android2.0开始之后drawable文件被三个文件夹drawable-hdpi,drawable-mdpi,drawable-ldpi三个文件夹所取代,有些编程人员为了让应用程序默认地加载某些图片,他们会特意地去在android2.0之后的应用程序中重新创建drawable文件夹,其实这样做完全没有必要,通过第一段的分析我们得知,android:anyDensity="false",则应用会将大小密度转变成中密度,从而去加载mdpi中的资源。这里同样,当android:anyDensity="false",则应用会去加载mdpi中的资源。
总结一下:
第一:android:anyDensity="true",系统会依据屏幕密度,自动去找对应的文件夹
第二:android:anyDensity="false",
(1) 如果drawable-hdpi,drawable-mdpi,drawable-ldpi三个文件夹中有同一张图片资源的不同密度表示,那么系统会去加载drawable_mdpi文件夹中的资源
(2) 如果drawable-hpdi中有高密度图片,其它两个文件夹中没有对应图片资源,那么系统会去加载drawable-hdpi中的资源。
(3) 如果drawable-hdpi,drawable-mdpi中有图片资源,drawable-ldpi中没有对应的图片资源,那么系统会加载drawable-mdpi文件夹中的资源
3. 注意上图各种文件夹的不同表示。
drawable-hdpi 该图片即适用于横屏,也适用于竖屏
drawable-land-hdpi,当屏幕为横屏,且为高密度时,加载此文件夹中的资源
drawable-port-hdpi,当屏幕为竖屏,且为高密度时,加载此文件夹中的资源
3. 有时候会根据需要在代码中动态地设置某个值,比如地图,地图的pin和地图的地址提示框的相对偏移量在不同密度的手机上是不同的。这时候可以通过以下方法求出屏幕密度:
DisplayMetrics metric = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metric);
int densityDpi = metric.densityDpi; // 屏幕密度DPI(120 / 160 / 240)
然后可以在代码中为这几种密度分别设置便宜量
但是这种方法最好不要使用,最好的方式是在xml文件中不同密度的手机进行分别设置。
这里地图的偏移量可以在values-hpdi,values-mdpi,values-ldpi三种文件夹中的dimens.xml文件进行设置
值得一提的是:
<dimen name="bitmap_common_topoffset">40dp</dimen>
<dimen name="bitmap_common_bottomoffset">-14dp</dimen>
这里的负数是完全起作用的,系统会认为它是一个负值
4. 各大手机厂商对于Android操作系统都有或多或少的改动,当然这些改动会对我们应用程序产生某些影响
比如:
(1)系统源代码中连接music服务的aidl文件所在包名:com.android.music
(2)LG则可能将该aidl文件修改所在的包(例如修改为 com.android.music.player),并且修改其中的文件内容(增加一个方法,或者减少几个方法,或者修改方法名称)那么我们的应用要想在LG的手机上发布,那么我们就必须改变所要连接的aidl文件,必须跟LG厂商修改的完全一致。
刚开始,我开发时选取的模拟器是
WVGA854
,其分辨率为
854*480
。我开发完毕后装在
800*480
的手机上时感觉很
OK
,但是装到
480*320
、以及
320*240
分辨率上的手机时,很多界面都变形了,这时我感受到了
app
自适应的重要性。
自适应主要会遇到两个大问题:横屏和竖屏的切换,以及分辨率大小不同。
一
.
当横屏切换成竖屏时,解决的办法:
在
res
目录下建立
layout-port
和
layout-land
两个目录,里面分别放置竖屏和横屏两种布局文件,当手机屏幕方向变化的时
android
系统会自动调用相应的布局文件。
当然还有办法就是不切换。要么都是横屏或者要么都是竖屏。可以在
AndroidManifest.xml
文件中设置,比如某个
Activity
设置为
android:screenOrientation="portrait"
这样就一直保持竖屏,如果设置为
android:screenOrientation="landscape"
这样就一直保持横屏。
二
.
当遇到分辨率不同大小时,我们也会遇到三个问题:图片大小、布局、横屏和竖屏的切换。
图片问题好解决,到
android2.0
以后的
api
中,我们会发现原先的
drawable
文件夹变成了
3
个分别是
drawable-hdpi
、
drawable-mdpi
、
drawable-ldpi
。
第一个文件夹放高分辨率手机的图片,比如:
854*480
、
800*480
第二个文件夹放中分辨率手机的图片,比如:
480*320
第三个文件夹放低分辨率手机的图片,比如:
320*240
关于布局和横屏切换成竖屏类似,也只需要在
res
目录下创建不同的
layout
文件夹,比如
layout-480x320,layout-800x480
,系统会根据屏幕的大小自己选择合适的
layout
来使用。
layout
是适配高分辨率竖屏的布局文件夹
layout-land
是适配高分辨率横屏的布局文件夹
layout-land-320x240
是适配低分辨率横屏的布局文件夹
layout-land-480x320
是适配中分辨率横屏的布局文件夹
layout-port-320x240
是适配低分辨率竖屏的布局文件夹
layout-port-480x320
是适配中分辨率竖屏的布局文件夹
这样布局文件的适配就做完了。
我个人觉得先按照高分辨率的模拟器开发效果比较好,然后去做各个不同分辨率的适配。有时候我们布局时,低分辨率的布局可能需要修改下。
[mw_shl_code=java,true]最后,还有一个问题如果是在java程序中写死的布局怎么办? 这个就很恼火了,需要判断屏幕的大小了,获取屏幕大小的代码如下: WindowManager windowManager = getWindowManager(); Display display = windowManager.getDefaultDisplay(); int screenWidth = display.getWidth();
int screenHeight = display.getHeight(); [/mw_shl_code][mw_shl_code=java,true] 下面的代码片段是我自己在程序中写死布局使用的,仅供参考:
Button cancelBtn = new Button(this); if (screenWidth<320 || screenHeight<320) cancelBtn.setLayoutParams(new LayoutParams(60, android.view.ViewGroup.LayoutParams.WRAP_CONTENT)); else if (screenWidth <480 &&screenHeight == 480) cancelBtn.setLayoutParams(new LayoutParams(80, android.view.ViewGroup.LayoutParams.WRAP_CONTENT)); else if (screenWidth >480 && screenHeight == 480) cancelBtn.setLayoutParams(new LayoutParams(160, android.view.ViewGroup.LayoutParams.WRAP_CONTENT)); else cancelBtn.setLayoutParams(new LayoutParams(120,
android.view.ViewGroup.LayoutParams.WRAP_CONTENT)); [/mw_shl_code]
|
-
图片1.png (8.2 KB, 下载次数: 10)
文件夹 当横屏切换成竖屏时,就会遇到一个问题,我该怎么创建layout文件夹? 下图是我的工程里所有的layo ...
测试时,发现应用在不同的显示器上显示效果不同(部分文本不能显示完全),自然想到屏幕适配的问题。
按照思路整理如下:
(一) 几个概念
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
如下图所示:
B, Drawable
如下图所示:
在drawable中,以mdpi为标准(即160dpi)。比例保持为3:4:5:6,如下图所示:
多分辨率支持
在设计之初,Android系统就被设计为一个可以在多种不同分辨率的设备上运行的操作系统。对于应用程序来说,系统平台向它们提供的是一个稳定的,跨平台的运行环境,而关于如何将程序以正确的方式显示到它所运行的平台上所需要的大部分技术细节,都由系统本身进行了处理,无需程序的干预。当然,系统本身也为程序提供了一系列API,所以在目标平台的分辨率是可以完全确定的情况下,程序也可以精确的控制自身在目标平台上的界面显示方式。
这个文档会说明系统平台究竟提供了哪些分辨率支持特性,与它们如何在程序中使用的信息。如果你遵循文档中列出的方法,就很容易让你的程序在所有支持的分辨率下都能完美显示。这样你就可以用一个单独的.apk文件,将你的程序发布到所有的平台上。
如果你已经发布过针对Android 1.5或更早版本平台的程序,你应该仔细阅读这篇文档,然后考虑一下到底如何让自己的老程序可以在拥有各种不同分辨率,并且运行着Android 1.6或更新平台上正常显示。在绝大部分情况下,只需要对程序作出小小的修改就可以达到目的,但你仍然需要尽可能地在各种分辨率的平台上进行测试。
特别的,如果你有一个已经完成的程序,又想让它可以在超低分辨率的设备(比如320×240)上正确运行,你需要阅读“老程序的更新策略”,那篇文档会告诉你应该怎么做。
术语和概念
屏幕尺寸
屏幕的物理尺寸,以屏幕的对角线长度作为依据(比如2.8寸,3.5寸)。
简而言之,Android把所有的屏幕尺寸简化为三大类:大,正常,和小。
程序可以针对这三种尺寸的屏幕提供三种不同的布局方案,然后系统会负责把你的布局方案以合适的方式渲染到对应的屏幕上,这个过程是不需要程序员用代码来干预的。
屏幕长宽比
屏幕的物理长度与物理宽度的比例。程序可以为制定长宽比的屏幕提供制定的素材,只需要用系统提供的资源分类符long和notlong。
分辨率
屏幕上拥有的像素的总数。注意,虽然大部分情况下分辨率都被表示为“宽度×长度”,但分辨率并不意味着屏幕长宽比。在Android系统中,程序一般并不直接处理分辨率。
密度
以屏幕分辨率为基础,沿屏幕长宽方向排列的像素。
密度较低的屏幕,在长和宽方向都只有比较少的像素,而高密度的屏幕通常则会有很多——甚至会非常非常多——像素排列在同一区域。屏幕的密度是非常重要的,举个例子,长宽以像素为单位定义的界面元素(比如一个按钮),在低密度的屏幕上会显得很大,但在高密度的屏幕上则会显得很小。
密度无关的像素(DIP)
指一个抽象意义上的像素,程序用它来定义界面元素。它作为一个与实际密度无关的单位,帮助程序员构建一个布局方案(界面元素的宽度,高度,位置)。
一个与密度无关的像素,在逻辑尺寸上,与一个位于像素密度为160DPI的屏幕上的像素是一致的,这也是Android平台所假定的默认显示设备。在运行的时候,平台会以目标屏幕的密度作为基准,“透明地”处理所有需要的DIP缩放操作。要把密度无关像素转换为屏幕像素,可以用这样一个简单的公式:pixels = dips * (density / 160)。举个例子,在DPI为240的屏幕上,1个DIP等于1.5个物理像素。我们强烈推荐你用DIP来定义你程序的界面布局,因为这样可以保证你的UI在各种分辨率的屏幕上都可以正常显示。
支持的屏幕分辨率范围
1.5及更早版本的Android系统,在设计的时候假定系统只会运行在一种分辨率的设备上——HVGA(320×480)分辨率,尺寸为3.2寸。由于系统只能工作在一种屏幕上,开发人员就可以针对那个屏幕来编写自己的程序,而无需去考虑程序在其他屏幕上的显示问题。
但自从Android 1.6以来,系统引入了对多种尺寸、多种分辨率屏幕的支持,以此满足拥有各种配置的新平台的运行需求。这就意味着开发人员在针对Android 1.6或更新版系统开发程序的时候,需要为自己的程序在多种分辨率的屏幕上良好显示作出额外的设计。
为了简化程序员面在对各种分辨率时的困扰,也为了具备各种分辨率的平台都可以直接运行这些程序,Android平台将所有的屏幕以密度和分辨率为分类方式,各自分成了三类:
·三种主要的尺寸:大,正常,小;
·三种不同的密度:高(hdpi),中(mdpi)和低(ldpi)。
如果需要的话,程序可以为各种尺寸的屏幕提供不同的资源(主要是布局),也可以为各种密度的屏幕提供不同的资源(主要是位图)。除此以外,程序不需要针对屏幕的尺寸或者密度作出任何额外的处理。在执行的时候,平台会根据屏幕本身的尺寸与密度特性,自动载入对应的资源,并把它们从逻辑像素(DIP,用于定义界面布局)转换成屏幕上的物理像素。
下表列出了Android平台支持的屏幕中一些比较常用的型号,并显示了系统是如何把它们分类到不同的屏幕配置里的。有些屏幕分辨率并不在下面的列表上,但系统仍会把它们归入下列的某一个类型中。
低密度(120),ldpi
中密度(160),mdpi
高密度(240),hdpi
小屏幕
·QVGA(240×320),2.6~3.0寸
普通屏幕
·WQVGA(240×400),3.2~3.5寸
·FWQVGA(240×432),3.5~3.8寸
·HVGA(320×480),3.0~3.5寸
·WVGA(480×800),3.3~4.0寸
·FWVGA(480×854),3.5~4.0寸
大屏幕
·WVGA(480×800),4.8~5.5寸
·FWVGA(480×854),5.0~5.8寸
如上表所示,所有分辨率的屏幕,都围绕在基准屏幕周围,而基准屏幕在分类中,为“正常”尺寸,与“中”密度。之所以用HVGA屏幕作为基准屏幕,是因为所有针对Android 1.5或更早的程序都是针对这片屏幕所写的(因为只支持这一片),比如T-Mobile G1。
虽然系统支持上面9种不同配置的屏幕,但你并不一定需要为它们都提供各自不同的资源。系统已经提供了足够鲁棒(就是在各种恶劣环境下正常工作,对环境变化不敏感)的兼容特性,用于在各种不同的屏幕上良好显示你的程序。这在下面的文档中会详细描述,如果你需要更多的资料,请查看“与屏幕无关的最佳实践”。