- 原文地址: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、前端、后端、区块链、产品、设计、人工智能等领域,想要查看更多优质译文请持续关注 掘金翻译计划、官方微博、知乎专栏。