1、概述
Android屏幕适配出现的原因
在我们学习如何进行屏幕适配之前,我们需要先了解下为什么Android需要进行屏幕适配。
由于Android系统的开放性,任何用户、开发者、OEM厂商、运营商都可以对Android进行定制,修改成他们想要的样子。
但是这种“碎片化”到底到达什么程度呢?
在2012年,OpenSignalMaps(以下简称OSM)发布了第一份Android碎片化报告,统计数据表明,
2012年,支持Android的设备共有3997种。
2013年,支持Android的设备共有11868种。
2014年,支持Android的设备共有18796种。
下面这张图片所显示的内容足以充分说明当今Android系统碎片化问题的严重性,因为该图片中的每一个矩形都代表着一种Android设备。
而随着支持Android系统的设备(手机、平板、电视、手表)的增多,设备碎片化、品牌碎片化、系统碎片化、传感器碎片化和屏幕碎片化的程度也在不断地加深。而我们今天要探讨的,则是对我们开发影响比较大的——屏幕的碎片化。
下面这张图是Android屏幕尺寸的示意图,在这张图里面,蓝色矩形的大小代表不同尺寸,颜色深浅则代表所占百分比的大小。
ab2d4007f2c7e9806436184f8b80a4d0.jpg
而与之相对应的,则是下面这张图。这张图显示了IOS设备所需要进行适配的屏幕尺寸和占比。
当然,这张图片只是4,4s,5,5c,5s和平板的尺寸,现在还应该加上新推出的iphone6和plus,但是和Android的屏幕碎片化程度相比而言,还是差的太远。
详细的统计数据请到这里查看。
现在你应该很清楚为什么要对Android的屏幕进行适配了吧?屏幕尺寸这么多,为了让我们开发的程序能够比较美观的显示在不同尺寸、分辨率、像素密度(这些概念我会在下面详细讲解)的设备上,那就要在开发的过程中进行处理,至于如何去进行处理,这就是我们今天的主题了。
但是在开始进入主题之前,我们再来探讨一件事情,那就是Android设备的屏幕尺寸,从几寸的智能手机,到10寸的平板电脑,再到几十寸的数字电视,我们应该适配哪些设备呢?
其实这个问题不应该这么考虑,因为对于具有相同像素密度的设备来说,像素越高,尺寸就越大,所以我们可以换个思路,将问题从单纯的尺寸大小转换到像素大小和像素密度的角度来。
下图是2014年初,友盟统计的占比5%以上的6个主流分辨率,可以看出,占比最高的是480*800,320*480的设备竟然也占据了很大比例,但是和半年前的数据相比较,中低分辨率(320*480、480*800)的比例在减少,而中高分辨率的比例则在不断地增加。虽然每个分辨率所占的比例在变化,但是总的趋势没变,还是这六种,只是分辨率在不断地提高。
所以说,我们只要尽量适配这几种分辨率,就可以在大部分的手机上正常运行了。
当然了,这只是手机的适配,对于平板设备(电视也可以看做是平板),我们还需要一些其他的处理。
好了,到目前为止,我们已经弄清楚了Android开发为什么要进行适配,以及我们应该适配哪些对象,接下来,终于进入我们的正题了!
首先,我们先要学习几个重要的概念。
- 什么是屏幕尺寸、屏幕分辨率、屏幕像素密度?
- 什么是dp、dip、dpi、sp、px?他们之间的关系是什么?
- 什么是mdpi、hdpi、xdpi、xxdpi?如何计算和区分?
- 在下面的内容中我们将介绍这些概念。
屏幕尺寸
屏幕尺寸指屏幕的对角线的长度,单位是英寸,1英寸=2.54厘米
比如常见的屏幕尺寸有2.4、2.8、3.5、3.7、4.2、5.0、5.5、6.0等
屏幕分辨率
屏幕分辨率是指在横纵向上的像素点数,单位是px,1px=1个像素点。一般以纵向像素*横向像素,如1960*1080。
屏幕像素密度
屏幕像素密度是指每英寸上的像素点数,单位是dpi,即“dot per inch”的缩写。屏幕像素密度与屏幕尺寸和屏幕分辨率有关,在单一变化条件下,屏幕尺寸越小、分辨率越高,像素密度越大,反之越小。
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类似,但是可以根据文字大小首选项进行放缩,是设置字体大小的御用单位。
mdpi、hdpi、xdpi、xxdpi
其实之前还有个ldpi,但是随着移动设备配置的不断升级,这个像素密度的设备已经很罕见了,所在现在适配时不需考虑。
mdpi、hdpi、xdpi、xxdpi用来修饰Android中的drawable文件夹及values文件夹,用来区分不同像素密度下的图片和dimen值。
dp适配:
一句话,总结下,dp能够让同一数值在不同的分辨率展示出大致相同的尺寸大小。但是当设备的尺寸差异较大的时候,就无能为力了。适配的问题还需要我们自己去做,于是我们可能会这么做:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- values-hdpi 480X800 -->
<dimen name="imagewidth">120dip</dimen>
</resources>
<resources>
<!-- values-hdpi-1280x800 -->
<dimen name="imagewidth">220dip</dimen>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- values-hdpi 480X320 -->
<dimen name="imagewidth">80dip</dimen>
</resources>
上述代码片段来自网络,也就是说,我们为了优质的用户体验,依然需要去针对不同的dpi设置,编写多套数值文件。
2.适配Tips
我们再来看看一些适配的tips
- 多用match_parent
- 多用weight
- 自定义view解决
其实上述3点tip,归根结底还是利用百分比,match_parent相当于100%参考父控件;weight即按比例分配;自定义view无非是因为里面多数尺寸是按照百分比计算的;
通过这些tips,我们更加的看出如果能在Android中引入百分比的机制,将能解决大多数的适配问题,下面我们就来看看如何能够让Android支持百分比的概念。
3、百分比的引入
Android屏幕适配方案里面的百分比引入以及快速生成dimen文件
Google已经添加了百分比支持库,详情请看:Android 百分比布局库
(percent-support-lib) 解析与扩展这里简单概述下。
android-percent-support-lib-sample
How to use :
just add percent support library to your project
dependencies {
compile 'com.android.support:percent:22.2.0'
}
支持的布局:
PercentRelativeLayout
<android.support.percent.PercentRelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<View
android:id="@+id/top_left"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_alignParentTop="true"
android:background="#ff44aacc"
app:layout_heightPercent="20%"
app:layout_widthPercent="70%" />
<View
android:id="@+id/top_right"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_alignParentTop="true"
android:layout_toRightOf="@+id/top_left"
android:background="#ffe40000"
app:layout_heightPercent="20%"
app:layout_widthPercent="30%" />
<View
android:id="@+id/bottom"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_below="@+id/top_left"
android:background="#ff00ff22"
app:layout_heightPercent="80%" />
</android.support.percent.PercentRelativeLayout>
PercentLinearLayout
<com.juliengenoud.percentsamples.PercentLinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<View
android:layout_width="0dp"
android:layout_height="0dp"
android:background="#ff44aacc"
app:layout_heightPercent="10%"
app:layout_widthPercent="60%"/>
<View
android:layout_width="0dp"
android:layout_height="0dp"
android:background="#ff4400cc"
app:layout_heightPercent="10%"
app:layout_widthPercent="70%"/>
</com.juliengenoud.percentsamples.PercentLinearLayout>
PercentFrameLayout
<android.support.percent.PercentFrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- ... XML CODE -->
</android.support.percent.PercentFrameLayout>
支持的属性 :
heightPercent
widthPercent
marginBottomPercent
marginEndPercent
marginLeftPercent
marginPercent
marginRightPercent
marginStartPercent
marginTopPercent
Pre-requisites
环境配置要求:
Android SDK v22
Android Build Tools v22.0.1
Android Percent Support Repository v22.2.0
Android Support v4 Repository v22.2.0
according to the the manifest minsdk is v7 (android 2.1)
详细分析这个库的源码:
Android 百分比布局库(percent-support-lib) 解析与扩展
其实主要就几个步骤:
- LayoutParams中属性的获取
- onMeasure中,改变params.width为百分比计算结果,测量
- 如果测量值过小且设置的w/h是wrap_content,重新测量
- onLayout中,重置params.w/h为布局文件中编写的值
可以看到,PercentLinearLayout,PercentRelativeLayout,PercentFrameLayout就是对LinearLayout,RelativeLayout、FrameLayout的扩展。
缺陷与完善
存在的缺陷:有些场景使用并不能满足我的要求
1. 当使用图片时,无法设置宽高的比例
比如我们的图片宽高是200*100的,我们在使用过程中我们设置宽高为20%、10%,这样会造成图片的比例失调。为什么呢?因为20%参考的是屏幕的宽度,而10%参考的是屏幕的高度。
2.很难使用百分比定义一个正方形的控件
比如,我现在界面的右下角有一个FloatingActionButton,我希望其宽度和高度都为屏幕宽度的10%,很难做到。
3.一个控件的margin四个方向值一致
有些时候,我设置margin,我希望四边的边距一致的,但是如果目前设置5%,会造成,上下为高度的5%,左右边距为宽度的5%。
综合上述这些问题,可以发现目前的percent-support-lib并不能完全满足我们的需求,所以我们考虑对其进行扩展。说白了,我们就希望在布局的时候可以自己设定参考看度还是高度,比如上述2,我们对于宽高可以写成10%w,10%w。也就是在不改变原库的用法的前提下,添加一些额外的支持。
二 扩展的功能
鸿洋大神对这个库的修改,github地址:android-percent-support-extend,对于官方库,做了如下的改变:
1.不改变原有库的用法
2.添加了PercentLinearLayout
3.支持百分比指定特定的参考值,比如宽度或者高度。
例如:
app:layout_heightPercent="50%w",
app:layout_marginPercent="15%w",
app:layout_marginBottomPercent="20%h".
4.支持通过app:layout_textSizePercent设置textView的textSize
5.对于外层套ScrollView的问题,目前可以在PercentLinearLayout的外层使用ScrollView,不过对于宽度的百分比参考的就是android.R.id.content的高度(因为,无法参考父控件的高度,父控件的高度理论上依赖于子View高度,且模式为UNSPECIFIED)
参考:
Android适配全攻略
Android 百分比布局库(percent-support-lib) 解析与扩展
Android 增强版百分比布局库 为了适配而扩展