Android屏幕适配
Android开发中,Android屏幕适配是一件很棘手的事,需要注意的几点:尽量使用线性布局(LinearLayout)和相对布局(RelativeLayout),不要使用绝对布局;尽量使用dip和sp,不要使用px;为不同的分辨率提供不同的布局文件和图片;在AndroidMainfest.xml中设置多分辨率支持。
AD:
对于从事android应用开发的朋友来说都应该知道,现在的安卓手机的屏幕类型十分繁多, 大小尺寸,长宽比例都不尽相同,同一个界面在不同分辨率的手机上可能出现布局错乱,控件跑位的现象。做屏幕的适配偶们不可能实现在每种屏幕上显示出的界面 效果完全一致。只能靠偶们平时的编程习惯和经验是的界面在不同的屏幕尺寸在不会出现过分的走位,在可遇见范围内控制界面在不同屏幕下的变化,并做出相应调 整。那么偶们应该如何做到屏幕的适配呢?下面我就以我的开发经验来说说吧。
1、首先从布局考虑
Android 的界面是由布局和组件协同完成的,布局好比是建筑里的框架,而组件则相当于建筑里的砖瓦。组件按照布局的要求依次排列,就组成了用户所看见的界面。 Android的五大布局分别是LinearLayout(线性布局)、FrameLayout(单帧布局)、RelativeLayout(相对布 局)、AbsoluteLayout(绝对布局)和TableLayout(表格布局)。
每种布局都有其特点,你可能会郁闷无法掌握好每种布局的使用,其实不管一个界面多复杂,偶们只需上述的一两种布局就可以实现,android提供这么多的布局供偶们选择只是为了方便偶们的开发。
本人习惯用LinearLayout,可能由于个人习惯,所以觉得线性布局的条理性更强一点,LinearLayout布局的子控件有一个很重要的属 性,android:layout_weight。该属性将会在后面讲到,在这里只是建议大家选择一种自己比较熟悉的布局,自己的条理性强点,在屏幕尺寸 发生变化时,能对子控件大小和位置的变化有一定的把握,这样才能做好屏幕适配。
2、px、dp和dip的关系
布局和子控件都有两个重要属性,layout_height和layout_width,用于指定控件的大小。系统还提供了几个属性供偶们使用,
1)fill_parent
设置一个构件的布局为fill_parent将强制性地使构件扩展,以填充布局单元内尽可能多的空间。这跟Windows控件的dockstyle属性大体一致。设置一个顶部布局或控件为fill_parent将强制性让它布满整个屏幕。
2) wrap_content
设置一个视图的尺寸为wrap_content将强制性地使视图扩展以显示全部内容。以TextView和ImageView控件为例,设置为 wrap_content将完整显示其内部的文本和图像。布局元素将根据内容更改大小。设置一个视图的尺寸为wrap_content大体等同于设置 Windows控件的Autosize属性为True。
3)match_parent
Android2.2中match_parent和fill_parent是一个意思 .两个参数意思一样,match_parent更贴切,于是从2.2开始两个词都可以用。那么如果考虑低版本的使用情况你就需要用fill_parent了。
更多情况下,为了界面可以适应不同屏幕分辨率的手机,偶们需要限制控件的大小,这里就要用到px、dp、dip、sp等等,这里只简单介绍下px和dip,其他在此不做阐述。
px: pixels(像素),不同的设备不同的显示屏显示效果是相同的,是绝对像素,是多少就永远是多少不会改变。 显然为了适配不同手机屏幕的显示,使用px来指定控件的大小是不行。
dip: device independent pixels(设备独立像素). 不同设备有不同的显示效果,这个和设备硬件有关,一般我们为了支持WVGA、HVGA和QVGA 推荐使用这 这个不依赖像素。
这里要特别注意dip与屏幕密度有关,而屏幕密度又与具体的硬件有关,硬件设置不正确,有可能导致dip不能正常显示。在屏幕密度为160的显示屏 上,1dip=1px,有时候可能你的屏幕分辨率很大如720*1280,但是屏幕密度没有正确设置比如说还是160,那么这个时候凡是使用dip的都会 显示异常,基本都是显示过小。
dip的换算:dip(value)=(int) (px(value)/1.5 + 0.5)
dp: 很简单,和dip是一样的。
所以在需要限定控件大小的时候,建议使用dip。
3、屏幕的分类
1)以总像素数分,文本的size等都要改,如下图所示:
每一个分类都有其最小分辨率,如下,可根据分辨率划分种类:
2)以屏幕密度分,提供不同的图片,如下图所示:
Android 寻找最佳资源原理:
1, 排除与设备设置不符合的资源
2, 根据限定词(qualifier)的优先级,按照顺序查找
3, 在限定词下,是否存在资源路径
4, 排除不包含在限定词中的资源路径
5, 继续执行不同的限定词查找,直到找到相应的资源
如下图所示:(提供英文版和中文版)
4、layout_weight属性
这个属性其实很好用,一般和android:layout_height="fill_parent"或 android:layout_width="fill_parent"一起使用,它用于描述该子元素在剩余空间中占有的大小比例。加入一行只有一个文本 框,那么它的默认值就为0,如果一行中有两个等长的文本框,那么他们的android:layout_weight值可以是同为1。如果一行中有两个不等 长的文本框,那么他们的android:layout_weight值分别为1和2,那么第一个文本框将占据剩余空间的三分之二,第二个文本框将占据剩余 空间中的三分之一。android:layout_weight遵循数值越小,重要度越高的原则。android屏幕如此繁多,不可能都是等比例缩放的, 所以单纯使用dip来设置控件也是行不通,与layout_weight属性灵活结合使用,增强界面的适应性。
5、drawable资源
首先:你需要在AndroidManifest.xml文件的元素如下添加子元素
- <supports-screens android:anyDensity="true" android:largeScreens="true" android:normalScreens="true" android:smallScreens="true" android:xlargeScreens="true" />
名如其意,以上是为我们的屏幕设置多分辨率支持(更准确的说是适配大、中、小三种密度)。android:anyDensity="true" ,这一句对 整个的屏幕都起着十分重要的作用,值为true,我们的应用程序当安装在不同密度的手机上时,程序会分别加载hdpi,mdpi,ldpi文件夹中的资 源。相反,如果值设置为false,即使我们在hdpi,mdpi,ldpi文件夹下拥有同一种资源,那么应用也不会自动地去相应文件夹下寻找资源,这种 情况都是出现在高密度,以及低密度的手机上,比如说一部240×320像素的手机,如果设置 android:anyDensity="false",Android系统会将240 x 320(低密度)转换为 320×480(中密度),这样的 话,应用就会在小密度手机上加载mdpi文件中的资源。
细心的人会发现自 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文件夹中的资源
注意上图各种文件夹的不同表示。
drawable-hdpi 该图片即适用于横屏,也适用于竖屏
drawable-land-hdpi,当屏幕为横屏,且为高密度时,加载此文件夹中的资源
drawable-port-hdpi,当屏幕为竖屏,且为高密度时,加载此文件夹中的资源
6、draw9patch工具
android SDK 包的tools目录下为偶们提供了这么一个图片处理工具。有时候偶们需要图片资源自适应且不失真,无论横屏还是竖屏,高分辨率还是低分辨率,都能自动填充 满,而且不失真等等背景问题。 Android针对这种情况,专门制作了一种.9.PNG格式来解决这个问题。draw9patch就是帮助偶们制 作.9.PNG格式资源的一个小工具。
*.9.PNG就标准的PNG格式,只是在最外面一 圈额外增加1px的边框,这个1px的边框就是用来定义图片中可扩展的和静态不变的区域。特别说明,left(左)和top(上)边框中交叉部分是可拉伸 部分,未选中部分是静态区域部分。right和bottom(下和右)边框中交叉部分则是内容部分。
如上图《也就是说,在手机里。无论上面那张图怎么放大,四周的圆角都是不会被放大的!只有left(左)和top(上)边框内才会伸缩!
在 Android中以9.PNG格式的图片未背景,则能够自定义拉伸而不失真,比如系统的Button就是一个典型的例子。其实呢,无论是left和 top,还是right和bottom都是把图片分成9块 (边角四块是不能缩放的,其他的四块则是允许缩放的),所以叫做9.PNG。
关于draw9patch工具的使用在此不做阐述,需要的可以自己去百度一下。
7、Layout资源
有时候可能由于屏幕布局过于复杂,同一个布局文件很难适应所有的屏幕分辨率。可以像drawable资源一样,在工程的res文件夹下建立多个相应的layout文件夹,为相应分辨率的屏幕编写相应的layout文件。
文件夹的命名规范是这样的:layout-分辨率
例如:layout-320x240 , layout-480x320等等。
系统就会根据运行环境的分辨率优先加载相应的文件夹下的layout布局文件。
8、代码动态添加
使用过swing的都知道如何代码动态添加控件,android也是一样的,当然代码动态添加远远没有xml布局文件方便,也不易于管理。但他的好处就是偶 们可以在代码里获得运行环境的屏幕尺寸,通过计算构建相应的界面。虽然代码编写界面确实繁琐,但他的适配性也是不可否认的。
获取屏幕的大小可以有两种方法:
// 方法一:
WindowManager manager = getWindowManager();
int width = manager.getDefaultDisplay().getWidth();
int height = manager.getDefaultDisplay().getHeight();
// 方法二:
DisplayMetrics dMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dMetrics);
int screenWidth = dMetrics.widthPixels;
int screenHeight = dMetrics.heightPixels;
然后就可以在代码中为这几种密度分别设置便宜量,但是这种方法最好不要使用,最好的方法是在xml文件中不同密度的手机进行分别设置。
这里地图的偏移量可以在values-hpdi,calues-mdpi,calues-ldpi三种文件夹中的dimens.xml文件进行设置。
值得一提的是:
<dimen name="bitmap_common_topoffset">40dp</dimen>
<dimen name="bitmap_common_bottomoffset">-14dp</dimen>
这里的负数是完全起作用的,系统会认为它是一个负值。
9、国家化问题
有时候在xml中设置了相应的语言,但是为什么当我们更改语言之后,UI显示仍然不起作用? 不要怀疑是系统出了问题,这与我们在代码中引用values/string.xml中字符串的方式有关。
错误的方式:
1. 声明全局变量 private static String tempStr;
2. 在onCreate方法中对该变量赋值 tempStr =context.getString(R.string.test);
3. 在更新UI的方法(非onCreate方法)中引用该变量。)textView.setText(tempStr);
原因是由于,当修改本地语言时,onCreate不会再被执行一遍. 变量tempStr 依然会使用页面刚启动时加载的默认英语。
正确的方式:直接进行第三步:textView.setText(context.getString(R.string.test));
10、其他
除了xml文件和代码编写界面外,还可以用webview加载相应的html文件,界面内容由html完成。本人见过别人用html5编写界面也非常美观,屏幕的适应性也非常强。由于本人对html5不是很了解,在此就不细谈,有兴趣的朋友可以去了解下。
有时候可能由于屏幕实在太小,要显示的内容又实在太多,一屏实在挤不下去。可以适当的使用ScrollView控件使界面更加完整,确保用户体验。
如何将一个应用程序适配在不同的手机上,虽然这不算是一个技术问题,但是对于刚刚做屏幕的开发人员来说,还真不是一件多么简单的事情。