- 原文地址:Using vector assets in Android apps
- 原文做者:Nick Butcher
- 譯文出自:掘金翻譯計劃
- 本文永久連接:github.com/xitu/gold-m…
- 譯者:YueYong
- 校對者:Rickon,TUARAN
在以前的文章中,咱們研究了 Android 的 VectorDrawable
圖像格式以及它可以實現的功能:html
在這篇文章中,咱們將會深刻研究如何在你的 app 中應用這些矢量資源。VectorDrawable
是在 Lollipop(API 21)中引入的,也能夠在 AndroidX 中使用(做爲 VectorDrawableCompat
),能夠向下兼容到 API 14(這使其能夠覆蓋超過 99% 的設備)。本文將概述一些能真正在你的應用中使用 VectorDrawables
的建議。android
從 Lollipop 開始,你能夠在任何須要使用其餘可繪製類型的地方使用 VectorDrawables
(使用標準的 @drawable/foo
語法引用它們),可是我建議始終使用 AndroidX 實現。ios
這會顯著增長其使用平臺的範圍,不只如此,它還支持將特性和 bug 修復程序向後移植到舊平臺。例如,使用 AndroidX 中的 VectorDrawableCompat
能夠:git
nonZero
和 evenOdd
路徑 fillTypes
—— 定義形狀「內部」的兩種常見方法,一般用於 SVGs(evenOdd
在 API 24 中得以實現)ColorStateList
填充 / 畫筆(在 API 24 中被添加實現)事實上,AndroidX 將使用 compat 實現,甚至在一些存在本地實現的平臺上(當前是 api 21-23)也能夠實現上述優勢。不然,它將委託給平臺實現,所以仍然能夠接收對新版本的任何改進(例如,爲了提升性能,VectorDrawable
在 API 24 的 C 中從新實現)。github
基於這些緣由,你應該始終使用 AndroidX,即便你很幸運地將你的 minSdkVersion
設置成 24。這沒什麼很差的,若是/當 VectorDrawable
在將來擴展了新的功能,而且它們也被添加到 AndroidX 中,那麼它們就能夠直接使用,而不須要從新檢查代碼。後端
Alex Lockwood 是這麼說的:api
爲了使用 AndroidX 矢量支持(AndroidX vector support),你須要作 2 件事情:緩存
您須要在應用的 build.gradle
中選擇加入 AndroidX
矢量支持:
android {
defaultConfig {
vectorDrawables.useSupportLibrary = true
}
}
複製代碼
若是 minSdkVersion
< 21,這意味着 Android Gradle 插件沒法生成矢量資源的 PNG 版本 —— 若是咱們使用 AndroidX 庫的話就不用擔憂這個問題。
經過默認的 AAPT(Android 資產包裝工具)版本資源。它也被傳遞給構建工具鏈。這意味着,若是你在 res/drawable/
中聲明一個 VectorDrawable
,它會爲你將其自動移動到 res/drawable-v21/
,由於系統知道這就是 VectorDrawable
類被引入的時候。
這能夠防止屬性 ID 衝突 —— 在
VectorDrawables
中使用的屬性(android:pathData
,android:fillColor
等)都有一個整數 ID,這些 ID 是在 API 21 中添加的。在老版本的 Android 上,沒有任何東西能夠阻止 OEM 使用任何"無人認領」的 ID,所以在較老的平臺上使用較新的屬性是不安全的。
這種版本控制將阻止在較老的平臺上訪問這些資源,使反編譯成爲不可能的事情 —— gradle 標誌禁用了可繪製對象資源(vector drawables)的版本控制。這就是爲何你使用 android:pathData
引入你的向量而不是必須切換到 app:pathData
等其餘後移功能。
當加載 drawables 時,你須要使用 AndroidX 的方法,由於它已經提供了對矢量資源的支持。這個的切入點是始終利用 AppCompatResources.getDrawable
加載 drawables。雖然有許多方法能夠加載 drawables(由於某些緣由),可是若是你想使用 compat 向量,就必須使用 AppCompatResources。若是你作不到這一點,那麼你就不能鏈接到 AndroidX 代碼路徑,當你嘗試使用任何你運行的平臺不支持的功能時,你的應用程序可能會崩潰。
VectorDrawableCompat
還提供了一個create
方法。 我老是會建議使用AppCompatResources
,由於這會增長一層緩存。
若是你想以聲明的方式設置 drawables(即在你的佈局中),appcompat
提供了一些 Compat
屬性,你應該使用這些屬性而不是標準的平臺屬性:
ImageView
,ImageButton
:
android:src
app:srcCompat
CheckBox
,RadioButton
:
android:button
app:buttonCompat
TextView
(as of appcompat:1.1.0
):
android:drawableStart
和 android:drawableTop
等app:drawableStartCompat
和 app:drawableTopCompat
等因爲這些屬性是 appcompat
庫的一部分,請確保使用 app: namespace。在內部,這些 AppCompat
視圖使用 AppCompatResources
來支持加載矢量的加載。
若是你想了解
appcompat
如何交換出TextView
,或者聲明瞭一個啓用此功能的AppCompatTextView
等,你能夠查看這篇文章:helw.net/2018/08/06/…
這些要求會影響你建立佈局或訪問資源所使用的方式。如下是一些考慮到的實際因素。
不幸的是,有不少地方你可能想要在不提供 compat 屬性的視圖上指定 drawables(例如,對於 progressbar
來講沒有 indeterminateDrawableCompat
屬性)。你仍然可使用 AndroidX vectors,但你須要對代碼做以下更改:
/* Copyright 2018 Google LLC.
SPDX-License-Identifier: Apache-2.0 */
val progressBar = findViewById<ProgressBar>(R.id.loading)
val drawable = AppCompatResources.getDrawable(context, R.drawable.loading_indeterminate)
progressBar.indeterminateDrawable = drawable
複製代碼
若是您正在使用數據綁定,那麼可使用自定義綁定適配器來完成此操做:
/* Copyright 2018 Google LLC.
SPDX-License-Identifier: Apache-2.0 */
@BindingAdapter("indeterminateDrawableCompat")
fun bindIndeterminateProgress(progressBar: ProgressBar, @DrawableRes id: Int) {
val drawable = AppCompatResources.getDrawable(progressBar.context, id)
progressBar.indeterminateDrawable = drawable
}
複製代碼
請注意,咱們不但願數據綁定爲咱們加載 drawable(由於它目前不使用 AppCompatResources
來加載 drawables),因此不能像 @ {@ drawable / foo}
那樣直接引用 drawable。相反,若是咱們想將 drawable id 傳遞給綁定適配器,所以須要導入 R
來引用它:
<!-- Copyright 2018 Google LLC.
SPDX-License-Identifier: Apache-2.0 -->
<layout ...>
<data>
<import type="your.package.R" alias="R" />
...
</data>
<ProgressBar ...
app:indeterminateDrawableCompat="@{R.drawable.foo}" />
</layout>
複製代碼
有些 drawable
是可嵌套的,例如 StateListDrawables
,InsetDrawables
或 LayerDrawables
均包含其餘子 drawable。AndroidX 支持顯式渲染 <vector>
元素(也包括動畫向量(animated-vector
)和動畫選擇器(animated-selectors
),但咱們今天主要討論靜態 vectors)。當你調用 AppCompatResources.getDrawable
,它用給定的 id
查看資源,若是它是一個向量(即根元素是 <vector>
),它就會手動地爲你加載它。不然,它就會把它交給系統加載——這樣作的時候,AndroidX 就沒法將本身從新插入到進程中。這意味着,若是你有一個包含向量的 InsetDrawable
,並利用 AppCompatResources
加載它,它將根據 <inset>
標記,而後將它交給平臺來加載。所以,它將沒有機會加載嵌套的 <vector>
,所以要麼加載失敗(在 API <21 上),要麼返回到平臺支持。
要解決這個問題,能夠在代碼中建立 drawables
;也就是說,使用 AppCompatResources
加載矢量資源,而後手動建立 InsetDrawable
格式的 drawable。
有一個例外是 AndroidX 最近添加了一個新功能(從 appcompat:1.0.0
開始)—— AnimatedStateListDrawables
向後移植(譯者注:原文是 back-ported ,Wikipedia 上解釋是把新版本上的東西移植到老版本上去
,這裏翻譯成向後移植)。這是 StateListDrawable
的一個版本,具備狀態之間的動畫轉換(以 AnimatedVectorDrawables
的形式)。你不須要申明一個過渡。所以,若是你只須要一個可使用 AndroidX 來擴充子向量的 StateListDrawable
,那麼你可使用:
<!-- Copyright 2018 Google LLC.
SPDX-License-Identifier: Apache-2.0 -->
<animated-selector ...>
<item android:state_foo="true" android:drawable="@drawable/some_vector" />
<item android:drawable="@drawable/some_other_vector" />
<!-- no transitions specified -->
</animated-selector>
複製代碼
一切都歸功於這個天才黑客: twitter.com/alexjlockwo…
有一種方法能夠在嵌套的 drawable 中啓用矢量,經過使用 AppCompatDelegate#setCompatVectorFromResourcesEnabled,但它有許多缺點。務必仔細閱讀 javadoc。
有時你須要在沒法控制什麼時候或如何加載的地方使用 drawable。例如:通知,主屏幕小部件或主題中指定的某些資源(例如,在建立預覽窗口時設置由平臺加載的 android:windowBackground
)。在這些狀況下,你不負責加載 drawable,所以沒有機會集成 AndroidX 支持,你也就沒法在 API 21 以前使用這些矢量資源了😞。
你固然能夠在 API 21+ 上使用 vectors,但請注意,你可能不喜歡 AndroidX 提供的功能/錯誤修正。例如,雖然 AndroidX 對 fillType="evenOdd"
支持的很好,可是在 API 21-23 設備上不使用 AndroidX 支持向量是沒法理解這個屬性的。對於這個具體的例子,我將在下一篇文章中介紹如何在設計時轉換 fillType。不然,你可能須要爲不一樣的 API 準備不一樣的資源了:
res/
drawable-xxhdpi/
foo.png <-- raster
drawable-anydpi-v21/
foo.xml <-- vector
drawable-anydpi-v24/
foo.xml <-- vector with fancy features
複製代碼
請注意,除了 api 級別限定符以外,咱們還須要在此處包含 anydpi
資源限定符。這是因爲資源限定符優先級的工做方式致使的。任何在 drawable- <whatever> dpi
中的資源都被認爲是比在 drawable-v21
更好的選擇。
本文旨在強調使用 AndroidX 矢量支持(AndroidX vector support)的好處以及一些你須要注意的限制。使用 AndroidX 支持既能夠在更多平臺版本和後端功能上使用矢量資源,也可讓你接收任何將來的更新。
如今咱們已經理解了爲何以及如何使用向量,下一篇文章將深刻探討如何建立它們。
即將推出:爲 Android 建立矢量資源
即將推出:Android VectorDrawables
分析
若是發現譯文存在錯誤或其餘須要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可得到相應獎勵積分。文章開頭的 本文永久連接 即爲本文在 GitHub 上的 MarkDown 連接。
掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源爲 掘金 上的英文分享文章。內容覆蓋 Android、iOS、前端、後端、區塊鏈、產品、設計、人工智能等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃、官方微博、知乎專欄。