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

_夏霂熠雨發表於2019-02-27

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

插圖來自 Virginia Poltrack

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

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

簡單的顏色

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

<!-- 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 線的交點的形狀)。不支援虛線描邊。

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

顏色資源

向量圖形中填充和描邊顏色的設定都支援 @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>
複製程式碼

這允許你可以提取顏色以便於維護,並幫助你約束應用程式的色調一致性。

它還允許你使用 Android 的 資源限定符 在不同配置中提供不同的顏色值。例如,你可以在夜間模式(res/colors-night/colors.xml)或如果 裝置支援寬色域res/colors-widecg/colors.xml)下提供替代的顏色值。

主題色

所有版本的向量(從 API14 到 AndroidX)都支援使用主題屬性(例如 ?attr/colorPrimary)來指定顏色。這些顏色是由主題提供的,對於建立靈活的資源非常有用,這種資源可以在應用的不同位置使用。

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

為 fills/strokes 設定主題色

你可以直接引用主題顏色來設定填充或描邊路徑:

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

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

</vector>
複製程式碼

如果你希望資源中的元素依據主題有所不同,那麼這是非常有用的。例如,一個體育型別的應用程式可以設定一個主題色的佔位符影象來顯示球隊的顏色;使用單一繪圖:

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

用主題顏色填充路徑

著色

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

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

    <path ... />

</vector>
複製程式碼

雖然你可以使用它來採取靜態著色,但它在與主題屬性組合時更有用。這允許您根據引入的主題更改整個資原始檔的顏色。例如,你可以使用 ?attr/colorControlNormal,它定義了圖示的標準顏色,並在明暗主題之間變化。這樣你就可以在不同主題的螢幕上使用一個圖示:

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

在明/暗螢幕上對圖示進行著色,使其具有適當的顏色

使用著色的一個好處是,你不需要依賴於你的資原始檔(通常來自你的設計師)是正確的顏色。對圖示使用 ?attr/colorControlNormal 屬性既能主題化,又能保證資原始檔的顏色完全相同、正確。

tintMode 屬性允許你更改用於著色繪製的混合模式,它支援:addmultiplyscreensrc_atopsrc_oversrc_in;對應於類似的 PorterDuff.Mode。通常你使用的預設屬性是 src_in,它將影象作為 alpha 蒙版應用於整個圖示,忽略單個路徑中的任何顏色資訊(儘管 alpha 通道是維護的)。因此,如果你打算給圖示著色,那麼最好使用完全不透明的填充/描邊顏色(慣例是使用 #fff)。

你可能想知道什麼時候為資源著色?什麼時候在單獨的路徑上使用主題顏色?因為這兩種顏色都可以獲得類似的結果。如果你只想在某些路徑上使用主題顏色,那麼必須直接使用它們。另一個需要考慮的問題是,你的資源是否具有重疊渲染。如果是這樣的話,那麼用半透明的主題顏色填充可能不會產生你想要的效果,但應用著色模式可能達到這種效果。

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

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

請注意,你可以通過設定 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 的引用。通過這種方式,你可以建立一個單獨的繪圖,其中路徑根據檢視/繪圖的狀態(如按下、選擇、啟用等)來改變顏色。

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

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

這是在 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 中使用多個可繪製物件也可以獲得類似的結果,但是如果狀態之間的呈現差異很小,則可以減少重複,並且更容易維護。

我也非常喜歡為自定義檢視建立自己的狀態,這些檢視可以與此支援結合使用,以控制資源中的元素,例如在某個特定狀態觸發之前將路徑設為透明。

漸變

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

支援 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 平鋪模式,這些模式……正如它們的名稱所暗示的那樣!在以下示例中,定義了一個徑向漸變:中心藍色 → 紫色圓形,但充滿更大的正方形路徑。

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

漸變平鋪模式

模式

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

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

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

插圖

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

另一幅由非常有才華的 Virginia Poltrack 繪製的可愛插圖

漸變在像插圖這樣的大型向量圖形中非常常見。向量圖非常適合插圖,但是在放大時要注意記憶體的權衡。我們將在本系列的後面討論這個問題。

陰影

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

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

使用漸變近似陰影

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

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

轉換包含漸變的路徑

顏色的數量

希望這篇文章已經表明 VectorDrawable支援許多高階特性,你可以使用這些特性在應用程式中渲染更復雜的資源,甚至可以用一個檔案替換多個資源,幫助你構建更精簡的應用程式。

我建議所有的應用程式都應該使用主題色彩的圖示。ColorStateList 和漸變支援就合適,但是如果你需要它,最好知道向量圖形支援的這些用例。

與向量圖形的相容性非常好,因此這些特性現在可以在大多數應用程式中使用(下一期將詳細介紹)。

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

即將展示:為 Android 建立向量資源 即將展示:分析 Android 的 VectorDrawable

感謝 Ben WeissDon TurnerDoris Liu

如果發現譯文存在錯誤或其他需要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可獲得相應獎勵積分。文章開頭的 本文永久連結 即為本文在 GitHub 上的 MarkDown 連結。


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

相關文章