给你一个全自动的屏幕适配方案(基于SW方案)!—— 解放你和UI的双手

原文地址:tangpj.com/2018/09/29/…php

简书地址:www.jianshu.com/p/6824ae172…git

Calces系列相关文章:Calces自动实现Android组件化模块构建github

前言

屏幕适配一直是移动端开发热议的问题,可是适配方案每每在实际开发的时候会和UI提供的设计稿冲突。本文主要是基于官方推荐的配置限定符方案(Smallest Width目前Android屏幕适配的最优方案)来实现一个接近完美的屏幕适配方案。app

原创声明: 该文章为原创文章,未经博主赞成严禁转载。maven

对于完美的适配方案笔者是这样定义的:编辑器

  1. 能完美适配UI稿。
  2. 适配完毕后,在高清设备上不会出现模糊的现象。
  3. 尽可能减小对项目的侵入性。

下面我会从屏幕适配的一些基础知识入手,向你慢慢展示一个最优的屏幕适配方案。工具

这是我写的Android构建辅助插件库,其中的Screen插件是实现自动屏幕适配的关键。由于怕你们错过这个插件,因此在这里提早推荐给你们。组件化

Screen插件主要提供两个功能:布局

  1. 配置设计稿密度与须要适配屏幕的Smallest Width值来自动生成对应的资源文件
  2. 提供须要的最高清的位图,根据须要缩放的密度自动缩放位图资源。

Github: 若是以为这个工具对您有帮助的话,能够点下Star,这是我坚持下去的动力💪测试

若是要深刻了解这个插件是如何自动帮你实现屏幕适配的,请仔细研读下文。

本文的Demo地址:DEMO。项目中的ScreenAdaptation就是本文的Demo。

屏幕适配概览

概念

  • 屏幕尺寸: 屏幕尺寸是指屏幕的物理尺寸,是经过测量屏幕的对角线测量出来的。

  • 屏幕密度: 屏幕物理区域中的像素量,一般称为dpi(每英寸的像素点数)。密度越高,现实效果越好。

  • 分辨率: 屏幕上物理像素的总数。在进行屏幕适配时,不要直接经过分辨率适配,应该经过屏幕尺寸和屏幕密度来适配

  • dp: dp是Android特有的虚拟像素单位,与物理参数无关。1dp等于160 dpi屏幕上的一个物理像素,在运行时,系统 根据使用中屏幕的实际密度按须要以透明方式处理 dp 单位的任何缩放 。dp 单位转换为屏幕像素很简单: px = dp * (dpi / 160)。在 240 dpi 屏幕上,1 dp 等于 1.5 物理像素。

如何支持多种屏幕

Android支持多种屏幕的基础是它可以针对当前屏幕的配置,以适当的方式渲染应用的布局和位图,这是由系统层面提供的支持。咱们能够经过如下方式来更好地处理不一样屏幕配置的适配:

  1. 为不一样的屏幕尺寸提供不一样的布局 默认状况下,Android会调整应用的布局大小以适应当前设备的屏幕,大多数状况下系统提供的支持就能知足咱们的须要。可是有时候须要针对不一样的屏幕分辨率来设计不一样的布局,以达到更好的现实效果。
  2. 为不一样的屏幕密度提供不一样的图片资源 咱们能够经过配置密度资源的配置限定符来提供不一样像素的图片,来适配不一样的屏幕密度。

对于第一点,在实际工做中是很难实现的。由于通常UI只会提供一套设计稿,不会根据不一样分辨率的屏幕来提供相应的适配。可是咱们没办法控制咱们的App最终会运行在什么分辨率的屏幕上,为了达到在不一样屏幕上的显示效果一直,咱们能够经过提供不一样密度的位图资源与Smallest Width方案来实现屏幕适配。

什么是Smallest Width适配

Smallest Width字面上的意思就是最小宽度,由可用屏幕区域的最小尺寸指定。 具体来讲,设备的 smallestWidth 是屏幕可用高度和宽度的最小尺寸。

例如,若是布局要求屏幕区域的最小尺寸始终至少为 600 dp,则可以使用此限定符建立布局资源 res/layout-sw600dp/。仅当可用屏幕的最小尺寸至少为 600dp 时,系统才会使用这些资源,而不考虑 600dp 所表明的边是用户所认为的高度仍是宽度。smallestWidth 是设备的固定屏幕尺寸特性;设备的 smallestWidth 不会随屏幕方向的变化而改变

因此咱们能够根据须要适配的屏幕的sw值来提供不一样的资源来实现屏幕适配。

UI设计与屏幕适配的一些基础理念

我以为不少屏幕适配教程都漏了一个很重要的点,就是:没有解释清楚屏幕适配与UI设计之间的关系!

通常在实际开发的时候,UI设计师都会提供一套UI稿与标尺,工程师是经过这套标尺来开发UI的。UI若是咱们要作好Android的屏幕适配,那么咱们必需要明白的一点就是,UI稿在咱们进行界面开发中是充当锚点的做用的。要适配其它的屏幕的话,必需要以这个基准为基础计算其它屏幕的dimens资源的值。

举个例子: 例如,不少UI设计师都会以iPhone6的尺寸做为标准来制做设计稿与标尺的,而iPhone6的屏幕宽度为375px,因此这个宽度为375px的设计稿就是咱们屏幕适配的基准了。

假设有一台sw等于375dp的设备的话,那么这个设备与设计稿对应的关系就是1dp = 1px,那么咱们就不须要进行任何适配,直接把设计稿以px为单位的标尺值以1:1的比例转换成以dp为单位就能够了。

在这里,咱们能够得出一个结论就是:屏幕适配须要以UI稿为基准再制定合适的适配方案!

可是有一个问题就是,每一个UI设计师的喜爱都是不同的,提供的设计稿的比例尺也不是固定的。并且Android的屏幕碎片化很是严重,咱们须要适配的屏幕的sw的值也是变化无穷的。因此若是每次都须要手动计算对应的dimens值的话,很是耗时间与繁琐。网上提供了一些工具来快速生成对应sw的dimens值,可是这些工具都会存在两个缺点:

  1. 没办法根据UI设计稿来转换,因此不必定能100%还原设计稿效果

  2. 会生成大量无用的dimens值。其实若是咱们细心观察过设计稿的话,咱们会发现,其实每份设计稿经常使用的px值都是固定的十来个。例如一样以375px的设计稿为基准的话,使用工具会生成1px ~ 375px对应的dp值,因此会存在大量的无用dimens值。这样只会徒增安装包的大小。

这个两个缺点,可使用笔者的calces.screen插件来解决,下文会介绍这个插件的使用方法与使用效果的。

使用calces.screen快速实现Smalles Widths适配方案

适配前与适配后对比状况

仍是以iPhone6的设计稿为例子,假若有下面这么一副设计稿,若是不进行任何适配的话,在不一样的设备上的显示效果对好比下:

第一个手机就是上文中说到的sw = 375dp的手机,咱们能够看到sw为其余值的手机上面,显示效果都不如意。在sw = 411dp和sw = 900dp的设备上,都留有大量的空白空间,而在sw = 360dp的设备上,则有超出屏幕范围的现象。咱们适配的目标就是:达到全部设备上显示的效果都和设计稿(sw = 375dp上的效果)一致。

使用calces.screen插件适配后的效果如图所示:

这里有一点须要注意的是,能够看到第三台设备里面的适配仍是有点问题,大概留下了1dp左右的白边。这个是pixel 2 XL的模拟器,能够看到,测量出来的sw值应该是411dp的,可是通过笔者的实际测量,发现sw应该是412dp才对。有兴趣的读者能够本身在布局编辑器里面建立一个width为411dp的控件,能够看到在pixel 2 XL设备下也是有大概1dp的白边的。因此这个1dp的偏差应该是和设备有关的,这里贴上用calces.screen生成的sw = 411dp的dimens文件的值观你们参考。

<resources>
  <!-- sw411dp -->
  <dimen name='px_48'>53dp</dimen>
  <dimen name='px_75'>83dp</dimen>
  <dimen name='px_100'>110dp</dimen>
  <dimen name='px_125'>137dp</dimen>
  <dimen name='px_150'>165dp</dimen>
  <dimen name='px_200'>220dp</dimen>
  <dimen name='px_250'>274dp</dimen>
  <dimen name='px_300'>329dp</dimen>
  <dimen name='px_375'>411dp</dimen>
  <dimen name='text_px_28'>31sp</dimen>
  <dimen name='text_px_32'>36sp</dimen>
  <dimen name='text_px_40'>44sp</dimen>
</resources>
复制代码

当sw = 411dp 时,px_375的实际值时411dp,因此这是符合咱们的预期转换结果的。

如何引入calces.screen

首先,咱们须要引入calces插件,引入的方式很简单:

在项目的build.gradle中添加代码:

//Gradle版本高于2.1的状况下(推荐方案)
plugins {
    id "calces.screen" version "1.2.3"
}

//Gradle版本低于2.1的状况下(2.1以上版本也兼容这种方式)
buildscript {
  repositories {
    maven {
      url "https://plugins.gradle.org/m2/"
    }
  }
  dependencies {
    classpath "gradle.plugin.com.tangpj.tools:calces:1.2.3"
  }
}

复制代码

在modules的build.gradle中添加代码:

apply plugin: "calces.appconfig"
复制代码

使用calces.screen适配屏幕

首先,咱们须要在res/values/文件夹中建立dimens.xml文件,而后按照设计稿的标尺把须要用到的尺寸写到该文件下。例如:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!--design 375px-->
    <dimen name="px_48">48dp</dimen>
    <dimen name="px_75">75dp</dimen>
    <dimen name="px_100">100dp</dimen>
    <dimen name="px_125">125dp</dimen>
    <dimen name="px_150">150dp</dimen>
    <dimen name="px_200">200dp</dimen>
    <dimen name="px_250">250dp</dimen>
    <dimen name="px_300">300dp</dimen>
    <dimen name="px_375">375dp</dimen>

    <!--text size-->
    <dimen name="text_px_28">28sp</dimen>
    <dimen name="text_px_32">32sp</dimen>
    <dimen name="text_px_40">40sp</dimen>
</resources>
复制代码

这就是咱们的基准dimens文件。

如今咱们只须要把基准尺寸与须要适配的尺寸经过Gradle配置就能够了,例如,上面的例子中,咱们须要适配的sw有:320dp, 411dp, 900dp,那么咱们须要在modules的build.gradle文件下添加以下代码:

screen{

    dimens{
        designPx 375
        smallesWidths 320,375,411,900
        scale BigDecimal.ROUND_UP
        auto true
    }

}
复制代码

上面配置信息的对应关系是:

  • designPx:设计稿的sw尺寸(单位px)

  • smallesWidths:须要适配的屏幕sw尺寸(单位dp)

  • scale: 数字取整的方式 由于Android系统只能适配整数单位的dp值,因此咱们能够经过scale来配置具体的取正方式。这里直接取BigDecimal提供的round来实现。若是不设置的话,则会生成double类型的dp值(实际使用的时候会丢弃小数位)

  • auto:是否自动生成dimens,当auto为true时,每次build都会从新生成一次适配dimens文件。 若是不设置auto或设置为false的话,能够手动调用gradle任务来生成。 调用命令: /gradlew dimensCovert 也能够直接点击gradle任务执行,方式以下图:

配置完毕后,从新build如下项目就能够看到生成的资源文件了,以下图:

为了避免影响编译时间auto建议设置为false,须要的时候再手动启动任务生成适配资源文件。

如何肯定咱们须要适配什么sw值?

除了自动生成sw外,咱们还须要肯定,咱们的App须要支持那些sw值。最简单的方法就是,先肯定咱们要支持哪些设备。这里笔者给出一个建议就是,市面上有很是多设备的sw值都是360dp的,因此咱们必需要适配360dp的设备。至于其它的设备,咱们能够这样来肯定,在开发者模式里面找到一项叫作最小宽度的参数,里面的值就是咱们须要的sw值。具体以下图:

Nexus S sw值

例如,上面这个是Nexus S的sw值。若是咱们不专门适配sw = 384dp的屏幕的话,那么系统就会默认寻找低于384dp的适配资源(因此360dp是一个相对通用的适配值)。当咱们拥有测试设备的时候,使用calces.screen适配是很是简单的。那么若是咱们不知道没有测试设备呢?(例若有用户反馈,某个设备下的适配有很大问题)

这里给你们推荐一个网站:Device Metrics

这个网站是Material Design的设备参数查找网站,用户在这里直接找到对应设备的尺寸就能够了(以前的方法翻车了,溜了溜了)。

通常状况下,sw为360dp和480dp的屏幕会比较常见,因此咱们必需要生成这两套资源,若是须要支持Pad的话,则须要适配sw = 600dp 或 sw = 720dp的屏幕,而后再根据实际状况适配其它sw值的屏幕。

到这里为止,咱们就完成了Android基于sw方案的屏幕适配了,很是简单!

可是,本文还没结束,这个插件除了提供自动实现基于sw方案的适配外,还提供了一个杀手级功能:根据配置自动把生成对应分辨率的位图资源。当咱们须要适配多种不一样屏幕密度的手机的时候,只须要提供一套高清位图资源就能够了,解放你和UI设计师的双手。

calces.screen实现位图自动缩放适配

为不一样密度的屏幕提供不一样的位图资源是Google官方推荐的屏幕适配作法。这样作的好处是,能使App在不一样密度的屏幕上都能达到最好的效果,不会出如今高清屏下出现老年机的显示效果,而且在不一样密度的屏幕下都能保持相对稳定的显示效果。下面是位图资源密度对应的比例关系:

密度限定符 比例关系 说明
ldpi 0.75 适用于低密度屏幕 (~120dpi) 的资源
mdpi 1 适用于中密度屏幕 (~160dpi) 的资源(基线密度)
hdpi 1.5 适用于高密度屏幕 (~240dpi) 的资源
xhdpi 2 适用于超高密度屏幕 (~320dpi) 的资源
xxhdpi 3 适用于超超高密度屏幕 (~480dpi) 的资源
xxxhdpi 4 适用于超超超高密度屏幕 (~640dpi) 的资源。此限定符仅适用于 启动器图标。

可是这里会产生一个问题,通常状况下,位图资源是UI设计师提供给咱们的。我和不少UI设计师讨论过,他们的方案就是先切一套最高清的图片,而后再根据须要进行缩放,而后提供给工程师使用。

通常状况下,这种作法除了繁琐点也没什么问题。可是若是如今出现了一个状况,就是须要支持更低密度的屏幕呢?这种状况只能让UI设计师再缩放一套密度的位图。那若是某部分位图已经再也不使用了,须要删除呢?那工程师须要把其它密度的位图找出来再删除。并且再往工程里面添加新的位图的时候也须要手工添加。

因此通常状况下,UI提供图片资源 —— 工程师使用图片资源这个过程当中是纯手工控制的。工做很是繁琐而且没什么意义,并且手动迁移的过程当中还很是容易出错(想一想若是复制漏了某几个密度的位图资源会是什么画面?)。因此calces.screen还提供了位图管理功能。

calces.screen管理位图

使用Screen的位图缩放功能以前,先和设计师/产品商量好App最高须要支持哪一个密度的屏幕。而后设计师之后只须要提供这套密度的位图就能够了。以后咱们只须要在modules的build.gradle中进行配置,配置方式以下:

screen{
    mipmap{
        designDensity "xxxhdpi" //测试用,目前手机屏幕最高只支持到xxhdpi
        mipmapDensity 'xxhdpi','xhdpi','hdpi','mdpi'
        auto true
    }

}
复制代码

配置完以后,从新build文件就能够了,固然不但愿增长编译时间的话,能够把auto置为false或者不设置。mipmap支持增量编译功能,只会对文件夹中不存在的位图进行缩放,已存在则跳过,识别条件是文件名。手动启动位图缩放功能的方式和上述方式一致,任务名称是mipmapZoom。下面咱们来看看转换效果:

转换前

转换后

读者能够点进去查看一下转换后的图片尺寸,能够发现,转换后的图片符合咱们须要的的比例。有兴趣的读者能够下载demo,把其它分辨率的位图资源删除,经过mipmapZoom任务从新生成。

经过mipmapZoom任务,能够大大减小UI设计师与工程师的工做量,只须要管理一套位图文件便可,把咱们从机械化的任务中解放出来。

注:目前版本不支持位图删除功能,因此当咱们须要删除部分位图的时候,须要把自动生成的图片文件所有删除,从新生成,后续版本会增长该功能。

结语

屏幕适配一直是移动端开发工程师的一大难题,面对琳琅满目的屏幕尺寸与屏幕密度,咱们一直在找一个更好的适配方案。Smallest Width是目前Android中最简单最好用的适配方案,没有之一,它是由系统提供支持的,而且在适配时不会由于屏幕分辨率与设计稿的差别过大形成一些奇奇怪怪的问题(大屏幕上面变糊,小屏幕又显得像素过于密集)。笔者这个适配方案是基于Smallest Width与提供多套位图为基础,经过Gradle插件来自动处理sw比例计算与文件生成、位图自动缩放来实现一个相对更好的适配方案。

calces.screen开发的初衷时简化UI设计师与Android工程师的工做量,目前已经基本达城这一目标。

好了,关于calces.screen插件的介绍就到此为止了,这里再一次提醒你们,若是以为calces对你有所帮助的话,能够点下star,鼓励下做者。若是有一些更好的想法的话,能够参与这一开源项目。笔者会一直维护这个项目的,致力于减轻Android工程师的负担,把重复的机械性工做所有交给Gradle来处理。

Github: 若是以为这个工具对您有帮助的话,能够点下Star,这是我坚持下去的动力💪

相关文章
相关标签/搜索