Android 三种适配方案

适配缘由

做Android开发一定会碰到适配这个问题,在Android世界里,Android设备太多了,手机,平板,TV,手表等,光其中的手机这一项就有众多厂家发布的奇奇怪怪的手机,不仅分辨率各有不同,就是手机尺寸也是一言难尽,各种尺寸都有,更烦的是有的手机还在屏幕上搞个虚拟导航栏放在底部;厂家多也就算了,由于Android系统的开源,任何厂家,个人,OEM厂商,运营商都可以对Android进行定制,修改成他们想要的样子,这更加大了适配的难度(尤其是我在平时开发中经常会用到一些工程机);总之而言,Android的碎片化太严重了;不像ios适配机型有限,所以解决掉Android适配问题是做一个好的APP的第一步

相关概念

在开发过程中,UI给出的设计图上的所有元素尺寸都是以px作为单位的,但是我们在layout文件中定义相关View的长宽是用dp作为单位来指定其值的,定义文字大小是用sp作为单位,还可能会涉及到屏幕尺寸,屏幕分辨率,屏幕像素密度dpi

这里说到了四个单位:px dp sp dpi,还有屏幕尺寸及屏幕分辨率:

屏幕分辨率:指手机横纵方向上的像素点数,比如常见的720 * 1280 ,1080 * 1920,单位px,1px=一个像素点,

屏幕尺寸:不是屏幕宽度,也不是长度,而是屏幕的对角线长度,比如常见的5.0尺寸,5.5尺寸,单位是英寸,1英寸=2.54厘米

dpi:全称dots per ich,也就是每英寸的像素点数(其实不是真正有多少像素点数),或者说屏幕像素密度;它是一个软件上的概念,是在系统软件上指定的单位尺寸的像素数量,它往往是写在系统出厂配置文件的一个固定值;我们可能还接触过一个单位叫ppi,它也是像素密度,这个是物理上的概念,它是客观存在的不会改变。dpi是软件参考了物理像素密度后,人为指定的一个值,这样保证了某一个区间内的物理像素密度在软件上都使用同一个值。这样会有利于我们的UI适配;比如,几部相同分辨率不同尺寸的手机的ppi可能分别是是430,440,450,那么在Android系统中,可能dpi会全部指定为480;ppi与屏幕尺寸和屏幕分辨率有关,它们的关系如下

dpi = \frac{\sqrt{ x^2 +y^2}}{屏幕尺寸}

px:这个大家容易理解,也就是真实像素的单位,就跟s是时间秒的单位一样

sp:全称scale-independent pixel,也叫sip,即独立缩放像素,Android特有的用来描述文字大小的单位,建议使用12,14,18,20等偶数值,避免奇数和小数造成精度的丢失问题;为什么用这个不用dp呢?这是因为我们可以在手机系统设置中修改文字的大小,如果使用dp单位,文字大小不会被改变;而使用sp会随着修改而变化;具体原因可参考sp与dp的区别

dp:全称Density-independent pixel 也叫dip,即独立像素密度,它的一个特性就是与像素无关,或者说与终端上的实际物理像素点无关,是Android特有的用来描述View尺寸的单位,保证同一个分辨率的图片在不同分辨率的手机上保持同样的视觉大小(占用相识比例的空间)

比如同样都是画一条长度是屏幕一半的线,如果使用px作为计量单位,那么在480x800分辨率手机上设置应为240px;在320x480的手机上应设置为160px,二者设置就不同了;如果使用dp为单位,在这两种分辨率下,160dp都显示为屏幕一半的长度,原因在下方

在Android中,规定以160dpi为基准,1dp=1px;320dpi下,1dp = 2px,计算公式:px = dp * (dpi / 160),屏幕密度越大,1dp对应 的像素点越多,如下表

这里还有一个东西没有提,mdpi、hdpi、xhdpi、xxhdpi、xxxhdpi等,它们是用来修饰Android中的mipmap(Eclipse中是drawable)文件夹及values文件夹,用来区分不同像素密度下的图片和dimen值,它们与dpi的关系如下



屏幕分辨率限定符

什么叫屏幕分辨率限定符呢?

我们知道市面上不同分辨率的手机太多太多了,而这种方案就是尽可能多的将其列举出来,在res目录下面创建与各种分辨率一一对应的values-xxx 文件夹;然后选定一种基准分辨率,然后其它分辨率以该分辨率做参考,生成对应的dimens文件,如图:


假设设计图上的一个控件的宽度为 720px,那么布局中就写 android:layout_width="@dimen/x720" ,当运行程序的时候,系统会根据设备的分辨率去寻找对应的 dimens.xml 文件。例如运行在分辨率为 1280x720 的设备上,系统会自动找到对应的 values-1280x720 文件夹下的 lay_x.xml 文件,由上图可知 x720 对应的值为

720.px,可铺满该屏幕宽度。运行在分辨率为 1920x1080 的设备上,系统会自动找到对应的 values-1920x1080 文件夹下的 lay_x.xml 文件,由上图可知 x720 对应的值为 1080.0px,可铺满该屏幕宽度。这样就达到了屏幕适配的要求

使用步骤

1、以设计图最小宽度(单位为 dp)作为基准值,生成所有设备对应的 dimens.xml 文件

这些文件当然不会手动去写,网上已经有大神提供了自动生成这些文件的插件ScreenMatch。但是这个插件还是有点问题的:

默认没有适配最小宽度为 320dp 的设备。其实自己测试还是有很多设备最小宽度是 320dp 的,所以需要加上。

最小宽度为 392.7272 与 411.4285 的手机不能达到完全适配。原因是该插件的默认值都是取整的,即 392.7272 与 411.4285 在插件中写的是 392 与 411。

基于以上问题,我在该插件的源码上优化生成了新的插件ScreenMatch,由于插件库已经有原作者的插件了,所以我就不重复造轮子上传到插件库了,你直接用本地安装的方式安装即可。

工具使用步骤:

在 Android Studio 中安装 ScreenMatch 插件

下载插件ScreenMatch到本地,点击菜单栏上的 File -> Settings -> Plugins -> Install plugin from disk,然后选择我们刚刚下载的插件,最后点击 “OK”,重启 Andorid Studio 即可。如下图所示:


2、在项目的默认 values 文件夹中需要一份 dimens.xml 文件


3、执行生成

插件安装好后,在项目的任意目录或文件上右键,选择 ScreenMatch 选项。如下图:



4、通过上面的步骤就已经生成了所有设备对应的 dimens.xml 文件。

根据设计图填写最小宽度基准值,并填写需要适配的设备最小宽度 dp 值

步骤 3 是以插件默认的最小宽度基准值为 360dp,适配的设备最小宽度为

320,360,384,392.7272,400,410,411.4285,432,480,533,592,600,640,662,720,768,800,811,820,960,961,1024,1280,1365(包含了平板和 TV )生成的文件,但实际情况要根据设计图和需求设置。

例如设计图的最小宽度为 375dp,则需要更改最小宽度基准值为 375dp。如果项目只需要适配手机的话,适配的设备最小宽度保留 320,360,384,392.7272,400,410,411.4285,432,480 即可,若发现手机还有其他最小宽度自行加上即可,也麻烦把该最小宽度提供给我,我们一起来完善该份适配。

以上修改需要在配置文件里修改,即 screenMatch.properties 文件,该配置文件是执行完上面第 3 步后自动生成在项目的跟目录下的。如下图:


AutoLayout适配

用法

(1) 引入autolayout

```

dependencies {

    compile project(':autolayout')

}

```

在你的项目的AndroidManifest中注明你的设计稿的尺寸。

```


<

meta-data android:name="design_width" android:value="768"></meta-data>

<meta-data android:name="design_height" android:value="1280"></meta-data>

```

(2)Activity中开启设配

让你的Activity去继承AutoLayoutActivity


今日头条适配方案(AutoSize)

使用步骤

1、添加依赖

```

api 'me.jessyan:autosize:1.1.2'

```

2、填写项目设计图尺寸

```

<manifest><application><meta-dataandroid:name="design_width_in_dp"android:value="540"/><meta-dataandroid:name="design_height_in_dp"android:value="960"/></application></manifest>

```

有两种类型的布局单位可以选择,一个是 主单位 (dp、sp),一个是 副单位 (pt、in、mm)

主单位: 使用 dp、sp 为单位进行布局,侵入性最低,会影响其他三方库页面、三方库控件以及系统控件的布局效果,但 AndroidAutoSize 也通过这个特性,使用 ExternalAdaptManager 实现了在不修改三方库源码的情况下适配三方库的功能

副单位: 使用 pt、in、mm 为单位进行布局,侵入性高,对老项目的支持比较好,不会影响其他三方库页面、三方库控件以及系统控件的布局效果,可以彻底的屏蔽修改 density 所造成的所有未知和已知问题,但这样 AndroidAutoSize 也就无法对三方库进行适配

到这里autosize的框架接入就已经完成了,已经能够实现autosize的基本功能了


进阶使用

在 AndroidManifest.xml 中填写的设计尺寸,是整个项目的全局设计图尺寸但是如果某些 Activity 页面由于某些原因,这个页面的设计图尺寸和在 AndroidManifest.xml 中填写的设计图尺寸不一样该怎么办呢?则可以让这个页面的 Activity 实现 CustomAdapt ,CustomAdapt 接口的第一个方法可以修改当前页面的设计尺寸。

```

publicclassCustomAdaptActivityextendsAppCompatActivityimplementsCustomAdapt{/**

    * 是否按照宽度进行等比例适配 (为了保证在高宽比不同的屏幕上也能正常适配, 所以只能在宽度和高度之中选择一个作为基准进行适配)

    *

    * @return {@code true} 为按照宽度进行适配, {@code false} 为按照高度进行适配

    */@OverridepublicbooleanisBaseOnWidth(){returnfalse;}/**

    * 设计图尺寸为 1080px * 1920px, 高换算成 dp 为 960 (1920px / 2 = 960dp)

    * <p>

    * 返回的设计尺寸, 单位 dp

    * {@link #getSizeInDp} 须配合 {@link #isBaseOnWidth()} 使用, 规则如下:

    * 如果 {@link #isBaseOnWidth()} 返回 {@code true}, {@link #getSizeInDp} 则应该返回设计图的总宽度

    * 如果 {@link #isBaseOnWidth()} 返回 {@code false}, {@link #getSizeInDp} 则应该返回设计图的总高度

    * 如果您不需要自定义设计图上的设计尺寸, 想继续使用在 AndroidManifest 中填写的设计图尺寸, {@link #getSizeInDp} 则返回 {@code 0}

    *

    * @return 单位 dp

    */@OverridepublicfloatgetSizeInDp(){return667;}}

```

如果你想放弃某个activity的适配你只需要实现 CancelAdapt 接口即可

```

public class CancelAdaptActivity extends AppCompatActivity implements CancelAdapt{

...

}

```

当你想要自定义fragment时你需要在app初始化时开启支持

在Applicationl类的oncreate方法中添加

```

AutoSizeConfig.getInstance().setCustomFragment(true);

```

万能解决方案

在任何情况下本来适配正常的布局突然出现适配失效,适配异常等问题,只要重写 Activity 的 getResources() 方法即可,如果是 Dialog、PopupWindow 等控件出现适配失效或适配异常,同样在每次 show() 之前调用 AutoSize#autoConvertDensity() 即可。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,366评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,521评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,689评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,925评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,942评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,727评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,447评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,349评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,820评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,990评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,127评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,812评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,471评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,017评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,142评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,388评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,066评论 2 355

推荐阅读更多精彩内容