[譯] 繪製路徑:Android 中矢量圖渲染

插圖來自 Virginia Poltrackhtml

在上一篇文章中,咱們研究了 Android 的 VectorDrawable 格式,瞭解了它的優勢和功能。前端

咱們討論瞭如何定義組成 assets 中形狀的路徑。VectorDrawable 支持許多實際繪製這些形狀的方法,咱們可使用這些方法建立豐富的、靈活的、可配置主題的和可交互的資源。在這篇文章中,我將深刻探討這些技巧:顏色資源、主題顏色、顏色狀態列表和漸變的使用。android

簡單的顏色

繪製路徑最簡單的方法是指定一種硬編碼的 fill/stroke 顏色。ios

<!-- Copyright 2018 Google LLC.
     SPDX-License-Identifier: Apache-2.0 -->
<vector ...>

    <path
      android:pathData="..."
      android:fillColor="#ff00ff"
      android:strokeColor="#999"
      android:strokeWidth="2"
      android:strokeLineCap="square" />

</vector>
複製代碼

你能夠定義這兩個屬性中的一個或者兩個,但每一個路徑只能應用一組 fill/stroke (這與某些圖形包不一樣)。首先繪製填充內容,而後繪製描邊內容。描邊老是居中的(不像一些圖形應用程序定義了內邊緣和外邊緣),它須要被明確的指定 strokeWidth 屬性,而 strokeLineCapstrokeLineJoin 屬性是能夠選擇性定義的,這些屬性控制描邊線的端點/鏈接處的形狀(也能夠定義 strokeMiterLimit 來控制 miter 線的交點的形狀)。不支持虛線描邊。git

填充和描邊都提供單獨的 alpha 屬性:fillAlphastrokeAlpha [0-1] 都默認爲 1,即徹底不透明。若是爲一個設置了 alpha 值的組件指定 fillColorstrokeColor,結果是這兩個值的結合。例如,若是指定 50% 透明的紅色 fillColor#80ff0000)和 0.5 的 fillAlpha,那麼結果將是 25% 透明的紅色。單獨的 alpha 屬性使路徑的不透明度更容易動畫化。github

顏色資源

矢量圖形中填充和描邊顏色的設置都支持 @color 資源的語法:後端

<!-- Copyright 2018 Google LLC.
     SPDX-License-Identifier: Apache-2.0 -->
<vector ...>

  <path
    android:pathData="..."
    android:fillColor="@color/teal"
    android:strokeColor="@color/purple"
    android:strokeWidth="2" />

</vector>
複製代碼

這容許你能夠提取顏色以便於維護,並幫助你約束應用程序的色調一致性。bash

它還容許你使用 Android 的 資源限定符 在不一樣配置中提供不一樣的顏色值。例如,你能夠在夜間模式(res/colors-night/colors.xml)或若是 設備支持寬色域res/colors-widecg/colors.xml)下提供替代的顏色值。app

主題色

全部版本的矢量(從 API14 到 AndroidX)都支持使用主題屬性(例如 ?attr/colorPrimary)來指定顏色。這些顏色是由主題提供的,對於建立靈活的資源很是有用,這種資源能夠在應用的不一樣位置使用。ide

使用主題顏色主要有兩種方式。

爲 fills/strokes 設置主題色

你能夠直接引用主題顏色來設置填充或描邊路徑:

<!-- Copyright 2018 Google LLC.
     SPDX-License-Identifier: Apache-2.0 -->
<vector ...>

  <path
    android:pathData="..."
    android:fillColor="?attr/colorPrimary" />

</vector>
複製代碼

若是你但願資源中的元素依據主題有所不一樣,那麼這是很是有用的。例如,一個體育類型的應用程序能夠設置一個主題色的佔位符圖像來顯示球隊的顏色;使用單一繪圖:

用主題顏色填充路徑

着色

<vector> 根元素提供了 tinttintMode 屬性值:

<!-- Copyright 2018 Google LLC.
     SPDX-License-Identifier: Apache-2.0 -->
<vector ...
  android:tint="?attr/colorControlNormal">

    <path ... />

</vector>
複製代碼

雖然你可使用它來採起靜態着色,但它在與主題屬性組合時更有用。這容許您根據引入的主題更改整個資源文件的顏色。例如,你可使用 ?attr/colorControlNormal,它定義了圖標的標準顏色,並在明暗主題之間變化。這樣你就能夠在不一樣主題的屏幕上使用一個圖標:

在明/暗屏幕上對圖標進行着色,使其具備適當的顏色

使用着色的一個好處是,你不須要依賴於你的資源文件(一般來自你的設計師)是正確的顏色。對圖標使用 ?attr/colorControlNormal 屬性既能主題化,又能保證資源文件的顏色徹底相同、正確。

tintMode 屬性容許你更改用於着色繪製的混合模式,它支持:addmultiplyscreensrc_atopsrc_oversrc_in;對應於相似的 PorterDuff.Mode。一般你使用的默認屬性是 src_in,它將圖像做爲 alpha 蒙版應用於整個圖標,忽略單個路徑中的任何顏色信息(儘管 alpha 通道是維護的)。所以,若是你打算給圖標着色,那麼最好使用徹底不透明的填充/描邊顏色(慣例是使用 #fff)。

你可能想知道何時爲資源着色?何時在單獨的路徑上使用主題顏色?由於這兩種顏色均可以得到相似的結果。若是你只想在某些路徑上使用主題顏色,那麼必須直接使用它們。另外一個須要考慮的問題是,你的資源是否具備重疊渲染。若是是這樣的話,那麼用半透明的主題顏色填充可能不會產生你想要的效果,但應用着色模式可能達到這種效果。

具備重疊路徑和半透明主題顏色的資源:比較着色和填充模式

請注意,你能夠經過設置 android:theme 屬性,在Activity/View 級別改變可繪製對象的主題,或者在代碼中使用 ContextThemeWrapper 設置一個特定的主題來 填充 這個矢量圖形。

/* Copyright 2018 Google LLC.
   SPDX-License-Identifier: Apache-2.0 */
val themedContext = ContextThemeWrapper(context, R.style.baz)
val drawable = AppCompatResources.getDrawable(themedContext, R.drawable.vector)
複製代碼

覆蓋主題 baz

顏色狀態列表

對於 填充/描邊,VectorDrawable 支持 ColorStateLists 的引用。經過這種方式,你能夠建立一個單獨的繪圖,其中路徑根據視圖/繪圖的狀態(如按下、選擇、激活等)來改變顏色。

矢量圖形對按下和選擇的狀態做出響應的例子

這是在 API24 中引入的,但最近添加到 AndroidX 中,從 1.0.0 版本也支持 API14。這也使用了 AndroidX 顏色狀態列表填充,這意味着你也能夠在 ColorStateList 中使用主題屬性和 alpha(它們自己只在 API23 中被添加到平臺中)。

<!-- Copyright 2018 Google LLC.
     SPDX-License-Identifier: Apache-2.0 -->
<selector ...>
  <item android:state_pressed="true"
    android:color="?attr/colorPrimary"
    app:alpha="0.8"/>
  <item android:color="#ec407a"/>
</selector>
複製代碼

雖然在 StateListDrawable 中使用多個可繪製對象也能夠得到相似的結果,可是若是狀態之間的呈現差別很小,則能夠減小重複,而且更容易維護。

我也很是喜歡爲自定義視圖建立本身的狀態,這些視圖能夠與此支持結合使用,以控制資源中的元素,例如在某個特定狀態觸發以前將路徑設爲透明。

漸變

支持 3 種類型的漸變

VectorDrawable 支持線性、徑向和掃描(也稱爲角)漸變的填充和描邊。在 AndroidX 包往前可支持到 API4 版本。漸變是在它們本身的文件中以 res/colors/ 的形式聲明的,可是咱們可使用 內嵌資源技術 來代替在矢量圖形中聲明的漸變,這樣更方便:

<!-- Copyright 2018 Google LLC.
     SPDX-License-Identifier: Apache-2.0 -->
<vector ...>
  <path android:pathData="...">
    <aapt:attr name="android:fillColor">
      <gradient .../>
    </aapt:attr>
  </path>
</vector>
複製代碼

在構建時,漸變被提取到它本身的資源中,並在父元素中插入對它的引用。若是要屢次使用相同的漸變,最好聲明一次並引用它,由於內聯版本每次都會建立一個新資源。

當指定漸變時,任何座標都位於根矢量元素的視覺空間中。讓咱們看看每一種漸變,以及如何使用它們。

線性

<!-- Copyright 2018 Google LLC.
     SPDX-License-Identifier: Apache-2.0 -->
<gradient
  android:type="linear"
  android:startX="12"
  android:startY="0"
  android:endX="12"
  android:endY="24"
  android:startColor="#1b82bd"
  android:endColor="#a242b4"/>
複製代碼

線性漸變必須指定 開始/結束的 X/Y 座標和 type="linear"

徑向

<!-- Copyright 2018 Google LLC.
     SPDX-License-Identifier: Apache-2.0 -->
<gradient
  android:type="radial"
  android:centerX="0"
  android:centerY="12"
  android:gradientRadius="12"
  android:startColor="#1b82bd"
  android:endColor="#a242b4"/>
複製代碼

徑向漸變必須指定一箇中心點 X/Y 的座標和一個半徑(一樣在視覺座標中),以及 type="radial"

掃描

<!-- Copyright 2018 Google LLC.
     SPDX-License-Identifier: Apache-2.0 -->
<gradient
  android:type="sweep"
  android:centerX="0"
  android:centerY="12"
  android:startColor="#1b82bd"
  android:endColor="#a242b4"/>
複製代碼

掃描漸變必須指定一箇中心點座標 X/ Y和 type="sweep"

起止顏色

漸變的使用很方便,你能夠直接在漸變中指定一個 startColorcenterColorendColor。若是你須要更細粒度的控制它或者設置更多起止顏色,你也能夠經過添加指定了 color 和 [0–1] offset(能夠把這個當作控制漸變程度的百分比)的子 item 來實現。

<!-- Copyright 2018 Google LLC.
     SPDX-License-Identifier: Apache-2.0 -->
<gradient ...>
  <item
    android:offset="0.0"
    android:color="#1b82bd"/>
  <item
    android:offset="0.72"
    android:color="#6f5fb8"/>
  <item
    android:offset="1.0"
    android:color="#a242b4"/>
</gradient>
複製代碼

平鋪模式

線性和徑向(不是掃描)漸變提供了平鋪的概念——也就是說,若是漸變沒有覆蓋它填充/描邊的整個路徑,那麼應該怎麼作。默認值是 clamp, 它只是延續開始/結束的顏色。或者你能夠指定 repeat 或者 mirror 平鋪模式,這些模式……正如它們的名稱所暗示的那樣!在如下示例中,定義了一個徑向漸變:中心藍色 → 紫色圓形,但充滿更大的正方形路徑。

漸變平鋪模式

模式

咱們能夠結合使用起止顏色和平鋪模式來實現矢量圖形中的基本模式支持。例如,若是指定了一致的起止顏色,就能夠實現忽然的顏色更改。將其與重複的平鋪模式結合起來,就能夠建立條紋模式。例如 這是一個由單個模式的填充形狀組成的加載指示器。經過在持有此模式的 group 上動畫化 translateX 屬性,咱們能夠實現如下效果:

注意,這種技術與完整的 SVG 模式 支持相去甚遠,但它可能頗有用。

插圖

另外一幅由很是有才華的 Virginia Poltrack 繪製的可愛插圖

漸變在像插圖這樣的大型矢量圖形中很是常見。矢量圖很是適合插圖,可是在放大時要注意內存的權衡。咱們將在本系列的後面討論這個問題。

陰影

VectorDrawables 不支持陰影效果;然而,簡單的陰影能夠用漸變來模擬實現。例如,這個 app 圖標使用徑向漸變來近似白色圓圈的投影,三角形下方的陰影使用線性漸變:

使用漸變近似陰影

一樣,這離徹底的支持陰影還有很長的路要走,由於只能繪製線性/徑向/掃描漸變,而不能沿着任意路徑繪製。你能夠近似一些形狀;特別是像以下 示例 對漸變元素應用變換,它使用 scaleY 屬性將一個徑向漸變的圓轉換成一個橢圓形來建立陰影:

轉換包含漸變的路徑

顏色的數量

但願這篇文章已經代表 VectorDrawable支持許多高級特性,你可使用這些特性在應用程序中渲染更復雜的資源,甚至能夠用一個文件替換多個資源,幫助你構建更精簡的應用程序。

我建議全部的應用程序都應該使用主題色彩的圖標。ColorStateList 和漸變支持就合適,可是若是你須要它,最好知道矢量圖形支持的這些用例。

與矢量圖形的兼容性很是好,所以這些特性如今能夠在大多數應用程序中使用(下一期將詳細介紹)。

加入咱們下一部分關於矢量圖形的探索:

即將展現:爲 Android 建立矢量資源 即將展現:分析 Android 的 VectorDrawable

感謝 Ben WeissDon TurnerDoris Liu

若是發現譯文存在錯誤或其餘須要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可得到相應獎勵積分。文章開頭的 本文永久連接 即爲本文在 GitHub 上的 MarkDown 連接。


掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源爲 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智能等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章
相關標籤/搜索