用脑思考,用心琢磨,用行动证实。
本讲内容:Android屏幕适配
一、下图是2014年友盟统计的占比5%以上的6个主流分辨率,可以看出,占比最高的是480*800,中高分辨率的比例则在不断地增加。所以我们只要适配这几种分辨率,就可以在大部分的手机上正常运行了。当然了,这只是手机的适配,对于平板设备(电视也可以看做是平板),我们还需要一些其他的处理。
二、了解什么是屏幕尺寸、屏幕分辨率、屏幕像素密度?
1、屏幕尺寸指屏幕的对角线的长度,单位是inch,1英寸=2.54厘米
2、屏幕分辨率是指在横纵向上的像素点数,单位是px,1px=1个像素点。一般以纵向像素*横向像素,如1920*1080。
3、屏幕像素密度是指每英寸上的像素点数,单位是dpi,即“dot per inch”的缩写。屏幕像素密度与屏幕尺寸和屏幕分辨率有关。dpi=(height^2+width^2)^1/2/屏幕尺寸
三、了解单位px、dp、dip、dpi、sp
1、分辨率是用px(像素)为单位的,大多数情况下,比如UI设计、Android原生API都会以px作为统一的计量单位,譬如获取屏幕宽高等。
2、dip和dp是一个意思,都是Density Independent Pixels的缩写,即密度无关像素,在Android中,规定以160dpi为基准,1dip=1px,如果密度是320dpi,则1dip=2px,以此类推。
假如同样都是画一条320px的线,在480*800分辨率手机上显示为2/3屏幕宽度,在320*480的手机上则占满了全屏,如果使用dp为单位,在这两种分辨率下,320dp都显示为屏幕的长度。这也是为什么在Android开发中,写布局的时候要尽量使用dp而不是px的原因。
3、sp是scale-independent pixels的缩写,与dp类似,可以根据文字大小进行放缩,是设置字体大小的御用单位。Google建议sp设置文字12sp以上,不要用小数或者奇数。
四、了解像素密度单位ldpi、mdpi、hdpi、xdpi、xxdpi
ldpi这个像素密度的设备已经很罕见了,所在现在适配时不需考虑。mdpi、hdpi、xdpi、xxdpi用来修饰Android中的drawable文件夹及values文件夹,用来区分不同像素密度下的图片和dimen值。
Google官方指定按照下列标准进行区分:
在进行开发的时候,我们需要把合适大小的图片放在合适的文件夹里面。下面以图标设计为例进行介绍。
在设计图标时,对于五种主流的像素密度(mdpi、hdpi、xdpi、xxdpi)应按照 2:3:4:6:8 的比例进行缩放。例如,一个启动图标的尺寸为48x48 dp,这表示在mdpi 的屏幕上其实际尺寸应为 48x48 px,在hdpi的屏幕上其实际大小是mdpi 的 1.5 倍 (72x72 px),依此类推。
下图为图标的各个屏幕密度的对应尺寸
通过使用配置限定符,在运行时根据当前的设备配置自动选择合适的资源了,提供最佳的用户体验。譬如怎样才能在运行时判断程序应该是使用双页模式还是单页模式,这就需要借助限定符来实现了。
参考例子 http://blog.csdn.net/liguojin1230/article/details/45172407
res/layout/activity_main.xml,单面板(默认)布局:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <fragment android:id="@+id/left_fragment" android:layout_height="fill_parent" android:name="com.example.fragmenttest.LeftFragment" android:layout_width="match_parent" /> </LinearLayout>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="horizontal"> <fragment android:id="@+id/left_fragment" android:layout_height="fill_parent" android:name="com.example.fragmenttest.LeftFragment" android:layout_width="0dp" android:layout_weight="1"/> <fragment android:id="@+id/right_fragment" android:layout_height="fill_parent" android:name="com.example.fragmenttest.RightFragment" android:layout_width="0dp" android:layout_weight="3"/> </LinearLayout>其中large就是一个限定符,那些屏幕被认为是large的设备( 例如 7 英寸或更大的平板电脑)就会自动加载 layout-large文件夹下的布局,而小屏幕的设备则还是会加载默认的layout文件夹下的布局
屏幕特征 | 限定符 | 描述 |
大小 | small | 提供给小屏幕设备的资源 |
normal | 提供给中等屏幕设备的资源 |
|
large | 提供给大屏幕设备的资源 |
|
xlarge | 提供给超大屏幕设备的资源 |
|
分辨率 | ldpi | 提供给低分辨率设备的资源(120dpi以下) |
mdpi | 提供给中等分辨率设备的资源(120dpi-160dpi) |
|
hdpi | 提供给高分辨率设备的资源(160dpi-240dpi) |
|
xhdpi | 提供给超高分辨率设备的资源(240dpi-320dpi) |
|
方向 | land | 提供给横屏设备的资源 |
port | 提供给竖屏设备的资源 |
六、使用最小宽度限定符
上面我们使用large限定符解决了单双页的判断问题,但是large到底指多大呢?有时候我们希望更加灵活发为不同设备加载布局,不管它们是否被系统认定为large,这时就可以使用最小宽度限定符了。
最小宽度限定符允许我们对屏幕的宽度指定一个最小值(以dp为单位),然后以这个最小值为临界点,屏幕宽度大于这个值的设备就加载这个布局。例如,标准 7 英寸平板电脑的最小宽度为 600 dp,因此如果您要在此类屏幕上的用户界面中使用双面板,您应使用 sw600dp 指明双面板布局仅适用于最小宽度为 600 dp 的屏幕,而不是使用 large 尺寸限定符。
在res目录下新建layout-sw600dp文件夹,然后在这个文件夹下新建activity_main.xml布局
res/layout-sw600dp/activity_main.xml,双面板布局:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="horizontal"> <fragment android:id="@+id/left_fragment" android:layout_height="fill_parent" android:name="com.example.fragmenttest.LeftFragment" android:layout_width="0dp" android:layout_weight="1"/> <fragment android:id="@+id/right_fragment" android:layout_height="fill_parent" android:name="com.example.fragmenttest.RightFragment" android:layout_width="0dp" android:layout_weight="3"/> </LinearLayout>当程度运行在屏幕宽度大于600dp的设备上时,会加载layout-sw600dp/activity_main布局,当程度运行在屏幕宽度小于600dp的设备上时,则仍然加载默认的layout/activity_main布局。
七、使用布局别名
最小宽度限定符仅适用于 Android 3.2 及更高版本。因此,如果我们仍需使用与较低版本兼容的概括尺寸范围(小、正常、大和特大)。例如,如果要将用户界面设计成在手机上显示单面板,但在 7 英寸平板电脑、电视和其他较大的设备上显示多面板,那么我们就需要提供以下文件:
res/layout/activity_main.xml: 单面板布局
res/layout-large: 多面板布局
res/layout-sw600dp: 多面板布局
后两个文件是相同的,因为其中一个用于和 Android 3.2 设备匹配,而另一个则是为使用较低版本 Android 的平板电脑和电视准备的。要避免平板电脑和电视的文件出现重复(以及由此带来的维护问题),您可以使用别名文件。例如,您可以定义以下布局:
res/layout/activity_main.xml,单面板布局
res/layout/activity_main_twopanes.xml,双面板布局
然后添加这两个文件:
res/values-large/layout.xml:
<resources> <item name="activity_main" type="layout">@layout/activity_main_twopanes</item> </resources>
<resources> <item name="activity_main" type="layout">@layout/activity_main_twopanes</item> </resources>后两个文件的内容相同,但它们并未实际定义布局。它们只是将 activity_main 设置成了 activity_main_twopanes 的别名。由于这些文件包含 large 和 sw600dp 选择器,因此无论 Android 版本如何,系统都会将这些文件应用到平板电脑和电视上(版本低于 3.2 的平板电脑和电视会匹配 large,版本高于 3.2 的平板电脑和电视则会匹配 sw600dp)。
八、使用自动拉伸位图
它是一种被特殊处理过的png图片,能够指定哪些区域可以拉伸以及不可以拉伸的区域。
.9的制作,实际上就是在原图片上添加1px的边界,然后按照我们的需求,把对应的位置设置成黑色线,系统就会根据我们的实际需求进行拉伸。
如下图:左上边代表拉伸区域(粉红线交集),右下边代表间隔区域(粉红线交集,可选的,表示该区域距离上下左右的距离确定了)
在Android sdk 目录下有一个tools文件夹有一个draw9patch.bat文件,双击打开它用来制作Nine-Patch图片的,点击File--Open 9-patch将图片加载进来。按下shift点点击鼠标左键移除黑点。
九、解决不同屏幕宽度问题
虽然用dp可以去除不同像素密度的问题,使得1dp在不同像素密度上面的显示效果相同,但是还是由于Android屏幕设备的多样性,如果使用dp来作为度量单位,并不是所有的屏幕的宽度都是相同的dp长度,比如说,Nexus S和Nexus One属于hdpi,屏幕宽度是320dp,而Nexus 5属于xxhdpi,屏幕宽度是360dp,Galaxy Nexus属于xhdpi,屏幕宽度是384dp,Nexus 6 属于xxxhdpi,屏幕宽度是410dp。所以说,光Google自己一家的产品就已经有这么多的标准,而且屏幕宽度和像素密度没有任何关联关系,即使我们使用dp,在320dp宽度的设备和410dp的设备上,还是会有90dp的差别。当然,我们尽量使用match_parent和wrap_content,尽可能少的用dp来指定控件的具体长宽,再结合上权重,大部分的情况我们都是可以做到适配的。
另一种解决办法 :
因为分辨率不一样,所以不能用px;因为屏幕宽度不一样,所以要小心的用dp,那么我们可不可以用另外一种方法来统一单位,不管分辨率是多大,屏幕宽度用一个固定的值的单位来统计呢?
参考http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023