- 原文地址:Draw a Path: Rendering Android VectorDrawables
- 原文做者:Nick Butcher
- 译文出自:掘金翻译计划
- 本文永久连接:github.com/xitu/gold-m…
- 译者:xiaxiayang
- 校对者:Mirosalva, siegeout
插图来自 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
属性,而 strokeLineCap
、strokeLineJoin
属性是能够选择性定义的,这些属性控制描边线的端点/链接处的形状(也能够定义 strokeMiterLimit
来控制 miter
线的交点的形状)。不支持虚线描边。git
填充和描边都提供单独的 alpha 属性:fillAlpha
和 strokeAlpha
[0-1] 都默认为 1,即彻底不透明。若是为一个设置了 alpha 值的组件指定 fillColor
或 strokeColor
,结果是这两个值的结合。例如,若是指定 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
使用主题颜色主要有两种方式。
你能够直接引用主题颜色来设置填充或描边路径:
<!-- Copyright 2018 Google LLC.
SPDX-License-Identifier: Apache-2.0 -->
<vector ...>
<path
android:pathData="..."
android:fillColor="?attr/colorPrimary" />
</vector>
复制代码
若是你但愿资源中的元素依据主题有所不一样,那么这是很是有用的。例如,一个体育类型的应用程序能够设置一个主题色的占位符图像来显示球队的颜色;使用单一绘图:
用主题颜色填充路径
<vector>
根元素提供了 tint
和 tintMode
属性值:
<!-- Copyright 2018 Google LLC.
SPDX-License-Identifier: Apache-2.0 -->
<vector ...
android:tint="?attr/colorControlNormal">
<path ... />
</vector>
复制代码
虽然你可使用它来采起静态着色,但它在与主题属性组合时更有用。这容许您根据引入的主题更改整个资源文件的颜色。例如,你可使用 ?attr/colorControlNormal
,它定义了图标的标准颜色,并在明暗主题之间变化。这样你就能够在不一样主题的屏幕上使用一个图标:
在明/暗屏幕上对图标进行着色,使其具备适当的颜色
使用着色的一个好处是,你不须要依赖于你的资源文件(一般来自你的设计师)是正确的颜色。对图标使用 ?attr/colorControlNormal
属性既能主题化,又能保证资源文件的颜色彻底相同、正确。
tintMode
属性容许你更改用于着色绘制的混合模式,它支持:add
、multiply
、screen
、src_atop
、src_over
或src_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"
。
渐变的使用很方便,你能够直接在渐变中指定一个 startColor
、centerColor
和 endColor
。若是你须要更细粒度的控制它或者设置更多起止颜色,你也能够经过添加指定了 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 绘制的可爱插图
渐变在像插图这样的大型矢量图形中很是常见。矢量图很是适合插图,可是在放大时要注意内存的权衡。咱们将在本系列的后面讨论这个问题。
VectorDrawable
s 不支持阴影效果;然而,简单的阴影能够用渐变来模拟实现。例如,这个 app 图标使用径向渐变来近似白色圆圈的投影,三角形下方的阴影使用线性渐变:
使用渐变近似阴影
一样,这离彻底的支持阴影还有很长的路要走,由于只能绘制线性/径向/扫描渐变,而不能沿着任意路径绘制。你能够近似一些形状;特别是像以下 示例 对渐变元素应用变换,它使用 scaleY
属性将一个径向渐变的圆转换成一个椭圆形来建立阴影:
转换包含渐变的路径
但愿这篇文章已经代表 VectorDrawable
支持许多高级特性,你可使用这些特性在应用程序中渲染更复杂的资源,甚至能够用一个文件替换多个资源,帮助你构建更精简的应用程序。
我建议全部的应用程序都应该使用主题色彩的图标。ColorStateList
和渐变支持就合适,可是若是你须要它,最好知道矢量图形支持的这些用例。
与矢量图形的兼容性很是好,所以这些特性如今能够在大多数应用程序中使用(下一期将详细介绍)。
加入咱们下一部分关于矢量图形的探索:
即将展现:为 Android 建立矢量资源 即将展现:分析 Android 的 VectorDrawable
感谢 Ben Weiss、Don Turner 和 Doris Liu。
若是发现译文存在错误或其余须要改进的地方,欢迎到 掘金翻译计划 对译文进行修改并 PR,也可得到相应奖励积分。文章开头的 本文永久连接 即为本文在 GitHub 上的 MarkDown 连接。
掘金翻译计划 是一个翻译优质互联网技术文章的社区,文章来源为 掘金 上的英文分享文章。内容覆盖 Android、iOS、前端、后端、区块链、产品、设计、人工智能等领域,想要查看更多优质译文请持续关注 掘金翻译计划、官方微博、知乎专栏。