給你一個全自動的屏幕適配方案(基於SW方案)!—— 解放你和UI的雙手

Calces系列相關文章:Calces自動實現Android組件化模塊構建git

本文簡書連接:https://www.jianshu.com/p/682...程序員

原文連接:http://tangpj.com/2018/09/29/...github

前言

屏幕適配一直是移動端開發熱議的問題,可是適配方案每每在實際開發的時候會和UI提供的設計稿衝突。本文主要是基於官方推薦的配置限定符方案(Smallest Width目前Android屏幕適配的最優方案)來實現一個接近完美的屏幕適配方案。微信

對於完美的適配方案筆者是這樣定義的:app

  1. 能完美適配UI稿。
  2. 適配完畢後,在高清設備上不會出現模糊的現象。
  3. 儘可能減小對項目的侵入性。

下面我會從屏幕適配的一些基礎知識入手,向你慢慢展示一個最優的屏幕適配方案。maven

這是我寫的Android構建輔助插件庫,其中的Screen插件是實現自動屏幕適配的關鍵。由於怕你們錯過這個插件,因此在這裏提早推薦給你們。編輯器

Screen插件主要提供兩個功能:工具

  1. 配置設計稿密度與須要適配屏幕的Smallest Width值來自動生成對應的資源文件
  2. 提供須要的最高清的位圖,根據須要縮放的密度自動縮放位圖資源。
Github: 若是以爲這個工具對您有幫助的話,能夠點下Star,這是我堅持下去的動力💪

若是要深刻了解這個插件是如何自動幫你實現屏幕適配的,請仔細研讀下文。組件化

本文的Demo地址:https://github.com/Tangpj/And...。項目中的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,這是我堅持下去的動力💪

關於我

若是你但願第一時間得到本人的最新文章的話,能夠關注個人微信公衆號:代碼以外的程序員。或者關注個人博客:http://tangpj.com

公衆號二維碼:

qr

相關文章
相關標籤/搜索