您的位置:首页 > 移动开发 > Android开发

Android 屏幕适配

2015-12-27 01:57 288 查看
Android为什么要进行适配

由于Android系统的开放性,任何用户、开发者、OEM厂商、运营商都可以对Android进行定制,修改成他们想要的样子。2014年OpenSignalMaps统计支持Android的设备共有18796种,屏幕尺寸这么多,为了让我们开发的程序能够比较美观的显示在不同尺寸、分辨率、像素密度(这些概念我会在下面详细讲解)的设备上,那就要在开发的过程中进行处理,

Android设备的屏幕尺寸,从几寸的智能手机,到10寸的平板电脑,再到几十寸的数字电视,我们应该适配哪些设备呢?其实这个问题不应该这么考虑,因为对于具有相同像素密度的设备来说,像素越高,尺寸就越大,所以我们可以换个思路,将问题从单纯的尺寸大小转换到像素大小和像素密度的角度来。

主要的分辨率有:480*800 720*1280 320*480 480*854 540*960 1080*1920

我们要适配这几种主要的分辨率,就可以在大部分的手机上正常运行了

重要概念

1)屏幕尺寸

屏幕尺寸指屏幕的对角线的长度,单位是英寸,1英寸=2.54厘米

比如常见的屏幕尺寸有2.4、2.8、3.5、3.7、4.2、5.0、5.5、6.0等

2)屏幕分辨率

屏幕分辨率是指在横纵向上的像素点数,单位是px,1px=1个像素点。一般以纵向像素*横向像素,如1960*1080。

3)屏幕像素密度

屏幕像素密度是指每英寸上的像素点数,单位是dpi,即“dot per inch”的缩写。屏幕像素密度与屏幕尺寸和屏幕分辨率有关,在单一变化条件下,屏幕尺寸越小、分辨率越高,像素密度越大,反之越小。屏幕像素密度=分辨率/尺寸

针对手机可以这样粗略的计算屏幕像素密度=(纵向像素纵向像素+横向像素横向像素)开平方/屏幕尺寸

4)dp、dip、dpi、sp、px

px我们应该是比较熟悉的,前面的分辨率就是用的像素为单位,大多数情况下,比如UI设计、Android原生API都会以px作为统一的计量单位,像是获取屏幕宽高等

dip和dp是一个意思,都是Density Independent Pixels的缩写,即密度无关像素,上面我们说过,dpi是屏幕像素密度,假如一英寸里面有160个像素,这个屏幕的像素密度就是160dpi,那么在这种情况下,dp和px如何换算呢?在Android中,规定以160dpi为基准,1dip=1px,如果密度是320dpi,则1dip=2px,以此类推。假如同样都是画一条320px的线,在480*800分辨率手机上显示为2/3屏幕宽度,在320*480的手机上则占满了全屏,如果使用dp为单位,在这两种分辨率下,160dp都显示为屏幕一般的长度。这也是为什么在Android开发中,写布局的时候要尽量使用dp而不是px的原因。

而sp,即scale-independent pixels,与dp类似,但是可以根据文字大小首选项进行放缩,是设置字体大小的御用单位。

5)mdpi、hdpi、xdpi、xxdpi

mdpi、hdpi、xdpi、xxdpi用来修饰Android中的drawable文件夹及values文件夹,用来区分不同像素密度下的图片和dimen值。

Google官方指定按照下列标准进行区分:

名称像素密度范围

mdpi 120dpi~160dpi

hdpi 160dpi~240dpi

xhdpi 240dpi~320dpi

xxhdpi 320dpi~480dpi

xxxhdpi 480dpi~640dpi

在设计图标时,对于五种主流的像素密度(MDPI、HDPI、XHDPI、XXHDPI 和 XXXHDPI)应按照 2:3:4:6:8 的比例进行缩放。例如,一个启动图标的尺寸为48x48 dp,这表示在 MDPI 的屏幕上其实际尺寸应为 48x48 px,在 HDPI 的屏幕上其实际大小是 MDPI 的 1.5 倍 (72x72 px),在 XDPI 的屏幕上其实际大小是 MDPI 的 2 倍 (96x96 px),依此类推。

下面为图标的各个屏幕密度的对应尺寸

屏幕密度图标尺寸

mdpi 48x48px

hdpi 72x72px

xhdpi 96x96px

xxhdpi 144x144px

xxxhdpi 192x192px

屏幕适配的主要方法

1)支持各种屏幕尺寸

(1)使用wrap_content、match_parent、weight

要确保布局的灵活性并适应各种尺寸的屏幕,应使用 “wrap_content” 和 “match_parent” 控制某些视图组件的宽度和高度。

使用 “wrap_content”,系统就会将视图的宽度或高度设置成所需的最小尺寸以适应视图中的内容,而 “match_parent”(在低于 API 级别 8 的级别中称为 “fill_parent”)则会展开组件以匹配其父视图的尺寸。

如果使用 “wrap_content” 和 “match_parent” 尺寸值而不是硬编码的尺寸,视图就会相应地仅使用自身所需的空间或展开以填满可用空间。此方法可让布局正确适应各种屏幕尺寸和屏幕方向。

android:layout_weight的真实含义是:如果View设置了该属性并且有效,那么该 View的宽度等于原有宽度(android:layout_width或者设置的具体值)加上剩余空间的占比,但是在真正用的时候,我们都是设置某一个属性为0dp,然后按照权重计算所占百分比

(2)使用相对布局,禁用绝对布局

在开发中,我们大部分时候使用的都是线性布局、相对布局和帧布局,绝对布局由于适配性极差,所以极少使用。由于各种布局的特点不一样,所以不能说哪个布局好用,到底应该使用什么布局只能根据实际需求来确定。

我们可以使用 LinearLayout 的嵌套实例并结合 “wrap_content”和 “match_parent”,以便构建相当复杂的布局。不过,我们无法通过 LinearLayout 精确控制子视图的特殊关系;系统会将 LinearLayout 中的视图直接并排列出。

如果我们需要将子视图排列出各种效果而不是一条直线,通常更合适的解决方法是使用 RelativeLayout,这样就可以根据各组件之间的特殊关系指定布局了。

2)支持各种屏幕密度

(1)使用非密度制约像素

由于各种屏幕的像素密度都有所不同,因此相同数量的像素在不同设备上的实际大小也有所差异,这样使用像素定义布局尺寸就会产生问题。因此,请务必使用 dp 或 sp 单位指定尺寸。dp 是一种非密度制约像素,其尺寸与 160 dpi 像素的实际尺寸相同。sp 也是一种基本单位,但它可根据用户的偏好文字大小进行调整(即尺度独立性像素),因此我们应将该测量单位用于定义文字大小。

因为分辨率不一样,所以不能用px;因为屏幕宽度不一样,所以要小心的用dp,尽量使用match_parent和wrap_content

(2)提供备用位图

由于 Android 可在具有各种屏幕密度的设备上运行,因此我们提供的位图资源应始终可以满足各类普遍密度范围的要求:低密度、中等密度、高密度以及超高密度。这将有助于我们的图片在所有屏幕密度上都能得到出色的质量和效果。

要生成这些图片,我们应先提取矢量格式的原始资源,然后根据以下尺寸范围针对各密度生成相应的图片。

xhdpi: 2.0

hdpi: 1.5

mdpi: 1.0(最低要求)

ldpi: 0.75

也就是说,如果我们为 xhdpi 设备生成了 200x200 px尺寸的图片,就应该使用同一资源为 hdpi、mdpi 和 ldpi 设备分别生成 150x150、100x100 和 75x75 尺寸的图片。

然后,将生成的图片文件放在 res/ 下的相应子目录中(mdpi、hdpi、xhdpi、xxhdpi),系统就会根据运行您应用的设备的屏幕密度自动选择合适的图片。

这样一来,只要我们引用 @drawable/id,系统都能根据相应屏幕的 dpi 选取合适的位图。

还记得我们上面提到的图标设计尺寸吗?和这个其实是一个意思。

但是还有个问题需要注意下,如果是.9图或者是不需要多个分辨率的图片,就放在drawable文件夹即可,对应分辨率的图片要正确的放在合适的文件夹,否则会造成图片拉伸等问题。

3)最佳实践

(1)关于高清设计图尺寸

Google官方给出的高清设计图尺寸有两种方案,一种是以mdpi设计,然后对应放大得到更高分辨率的图片,另外一种则是以高分辨率作为设计大小,然后按照倍数对应缩小到小分辨率的图片。

根据经验,我更推荐第二种方法,因为小分辨率在生成高分辨率图片的时候,会出现像素丢失。而分辨率可以以1280*720或者是1960*1080作为主要分辨率进行设计。

(2)ImageView的ScaleType属性

设置不同的ScaleType会得到不同的显示效果,一般情况下,设置为centerCrop能获得较好的适配效果。

(3)动态设置

有一些情况下,我们需要动态的设置控件大小或者是位置,比如说popwindow的显示位置和偏移量等,这个时候我们可以动态的获取当前的屏幕宽度和高度,然后设置合适的数值

4)其他适配点

(1)Android图片选择策略

如果屏幕所对应的文件夹没有要找的图片,怎么办。这是很常见的,我们开发项目时一般不会去为每一个级别的屏幕去切一套图片。那样做只会让apk很大。所以一般性的图片我们只切一两个典型密度屏幕的图片。但是apk是有可能会运行在从ldpi到xxhdpi的各种级别的手机上。这个时候就需要根据一定的策略去寻找图片了。

1,去屏幕密度对应的目录去找(也就是屏幕密度相差不大的目录)。如果找到就拿来用。

2,如果没找到,就去比这个密度高一级的目录里面去找,如果找到就拿来用。如果没找到就继续往上找。以此类推。

3,如果到了xxhdpi目录还没有找到的话,就会去比自身屏幕密度低一级的目录去找,如果低一级的目录>=hdpi,找到了就拿来用。如果没找到, 就去mdpi目录去找, 如果找到了,就拿来用。

6,如果没找到,就去默认的drawble目录里去找, 如果找到了就拿来用。

7,如果没找到,再去最低的ldpi目录里去找。如果找到了就拿来用。

8,如果没找到, 那就是没找到了, 图片无法显示。

这里有两点需要注意:

[1]首先会去比自己密度高的目录里去找,这是因为系统相信,你在密度更高的目录里会放置分辨率更大的图片,这样的话这个图片会被缩小,但同时显示效果不会有损失,但是如果优先去低一级别的目录去找的话, 找到的图片就会被放大,这样的话这个图片就会被拉扯模糊了

例如:(1)同一张图片,你在mdpi和xxhdpi目录各放了一份, 这个应用你现在运行在hdpi的手机上, 那应用会选择哪张图片呢。答案是xxhdpi目录里的。即便hdpi离mdpi更近一点!

[2]在mdpi里找不到是不会直接去ldpi里找的, 而是先去默认的drawble目录里找,这是drawble目录和drawble-mdpi是一个级别的。

(2)在代码中获取屏幕像素、屏幕密度

DisplayMetrics metric = new DisplayMetrics();

getWindowManager().getDefaultDisplay().getMetrics(metric);

int width = metric.widthPixels;// 屏幕宽度(像素)

int height = metric.heightPixels;// 屏幕高度(像素)

float density = metric.density;// 屏幕密度(0.75 / 1.0 / 1.5)

int densityDpi = metric.densityDpi;// 屏幕密度DPI(120 / 160 / 240)

(3)drawable资源

你需要在AndroidManifest.xml文件的元素如下添加supports-screens子元素

android:anyDensity=”true”//是否支持多种不同密度的屏幕

android:largeScreens=”true”//是否支持大屏

android:normalScreens=”true”//是否支持中屏

android:resizeable=”true”

android:xlargeScreens=”true”//是否支持超大屏

android:smallScreens=”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中的资源。

参考资料:/article/1580341.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: