如何将一个应用程序适配在不同的手机上,虽然这不算是一个技术问题,但是对于刚刚做屏幕的开发人员来说,还真不是一件多么简单的事情。
首先:你需要在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]
|