簡單看懂 VectorDrawable / SVG path data

設計師與工程師都該知道的事 ⑶

Dcard Tech
Dcard Tech Blog
10 min readMar 20, 2017

--

前言

這篇文的標題原本是「Android 向量圖形資源的進階運用」,同時包含了 AnimatedVectorDrawable 的介紹(然後打算這系列三篇文完結)。不過寫到後來覺得有點長,決定還是把動畫的部分拆開。

所以本系列可能會有第四篇⋯⋯吧。

本篇接續《為 Android app 準備圖形資源》《Android 點陣圖形資源的進階運用》,做一些關於圖形資源更進階的探討。

自從 Android 5.0 (API level 21) 以後,加入了 VectorDrawable 的圖形資源形式,但標準 Android 開發時使用的向量圖形不是放 SVG 或 PDF 等都適用,而是要轉換成結構相對簡單的 XML 描述檔。

初探 VectorDrawable 的格式

在了解 path data 指令之前,你可以先用自己的 SVG 檔案產生一個 VectorDrawable 做為參考。

Vector Asset 工具會自動為每個形狀填上黑色,所以產生後顏色資訊遺失黑黑一片是正常的。打開產生的 VectorDrawable xml 檔案,會看到類似以下格式的內容:

<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M12,12m-12,0a12,12 0,1 1,24 0a12,12 0,1 1,-24 0"/>
<path
android:fillColor="#FF000000"
android:pathData="M18.9,12l-10.4,-6l0,12z"/>
</vector>

稍微調整一下填色以及框線以後如下,作為後面解說的範例。

範例

<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="#006aa6"
android:pathData="M12,12m-12,0a12,12 0,1 1,24 0a12,12 0,1 1,-24 0"
android:strokeColor="#000"
android:strokeWidth="1"/>
<path
android:fillColor="#fff"
android:pathData="M18.9,12l-10.4,-6l0,12z"/>
</vector>
範例檔案的顯示效果

直線指令

指令

  • M(絕對)m(相對):“moveto” 「移動」
    參數: (x, y)+
    從現在位置移動畫筆到 (x, y) 的位置。
  • L(絕對)l(相對):“lineto” 「直線到」
    參數: (x, y)+
    從現在位置畫直線到 (x, y) 的位置。
  • H(絕對)h(相對):“horizontal lineto” 「水平線到」
    參數: x+
    從現在位置畫水平線到 x 的位置
  • V(絕對)v(相對):“vertical lineto” 「垂直線到」
    參數: y+
    從現在位置畫垂直線到 y 的位置。
  • Zz“closepath”「封閉路徑」
    無參數
    從現在位置畫一條直線到起始點,形成封閉路徑。

解釋範例

在範例中,你會看到簡單的向量圖形是由 fillstrokepath 等元素所構成。pathData 是有一連串指令所構成,與 SVG 檔案裡的 path 十分類似,也可以參考 W3C 的文件

範例中「白色三角形」的 path data 為:

M18.9,12l-10.4,-6l0,12z

拆開來看,一共有四個指令

M 18.9, 12
l -10.4, -6
l 0, 12
z
  • M 18.9, 12:移動(Move-to)畫筆到 (18.9, 12) 的位置
  • l -10.4, -6:畫一條直線路徑(Line-to)到相對原位置的 (-10.4, -6)
  • l 0, 12:畫一條直線路徑(Line-to)到相對原位置的 (0, 12)
  • z:封閉路徑
路徑 M18.9,12l-10.4,-6l0,12z 的解釋

範例簡化

上述範例也可以省略第二個 l 寫成

M 18.9, 12     l -10.4, -6     0, 12     z

或是將 0, 12 取代成垂直線寫成

M 18.9, 12     l -10.4, -6     v 12     z

曲線指令

斯斯有三種

圖片來源:https://disp.cc/b/115-2H47

曲線也有三種

  • 三次方貝茲曲線 Cubic Bézier (C, c, S, s):由一個起點、一個終點,以及兩個控制點所組成的貝茲曲線。
  • 二次方貝茲曲線 Quadratic Bézier (Q, q, T, t):由一個起點、一個終點,以及一個控制點所組成的貝茲曲線。
  • 橢圓弧曲線 Elliptical arc (A, a) :橢圓型一部分所構成的曲線。

指令

  • C(絕對)c(相對):“curveto”
    參數: (x1 y1 x2 y2 x y)+
    從目前的點繪製三次方貝茲曲線到 (x, y),以 (x1, y1) 為起點的控制點,(x2, y2) 為終點的控制點。
  • S(絕對)s(相對):“shorthand/smooth curveto”
    參數:(x2 y2 x y)+
    與 curveto 同樣繪製三次方貝茲曲線到 (x, y),只是將起點的控制點設為上一個控制點的鏡射。
  • Q(絕對)q(相對):“quadratic Bézier curveto”
    參數:(x1 y1 x y)+
    從目前的點繪製二次方貝茲曲線到 (x, y),以 (x1, y1) 為控制點。
  • T(絕對)t(相對):“shorthand/smooth quadratic Bézier curveto”
    參數:(x2 y2 x y)+
    與 quadratic Bézier curveto 同樣繪製二次方貝茲曲線到 (x, y),只是將控制點設為上一個控制點的鏡射。
  • A(絕對)a(相對):“elliptical arc”
    參數:(rx ry x-axis-rotation large-arc-flag sweep-flag x y)+
    從目前的點繪製橢圓弧到 (x, y),橢圓半徑為 (rx, ry),旋轉角度為 x-axis-rotationlarge-arc-flagsweep-flag 參數定義了橢圓弧的區段,示意圖如下。
elliptical arc 中,large-arc-flag、sweep-flag 的意義

貝茲曲線

在數學的數值分析領域中,貝茲曲線(英語:Bézier curve)是計算機圖形學中相當重要的參數曲線。在向量圖檔中,除了橢圓以外的曲線都是用貝茲曲線所表示。

三次方貝茲曲線 Cubic Bézier (C, c, S, s):由一個起點、一個終點,以及兩個控制點所組成的貝茲曲線。

我到底看了什麼?

如果你用過 Adobe Illustrator(或是其他向量繪圖軟體),應該覺得下圖很眼熟。游標移過去還會出現一些細明體小字,這就是貝茲曲線的結構。

貝茲曲線結構示意圖

下圖是四分之一圓弧用三次貝茲曲線的表示法,把手就是控制點,一共兩個端點與兩個控制點。除此之外,上圖的控制點(把手)就是鏡射的,所以你現在應該知道 shorthand/smooth curveto 的指令是什麼意思了。

四分之一圓弧的貝茲曲線結構

繪製曲線的原理,維基百科的頁面有一些動畫演示,有興趣可以去看看

工程師覺得療癒 。:.゚ヽ(*´∀`)ノ゚.:。

解釋範例

範例中的圓形部分的路徑指令是這樣

M12,12m-11.5,0a11.5,11.5 0,1 1,23 0a11.5,11.5 0,1 1,-23 0

拆開來看

M 12, 12
m -11.5, 0
a 11.5, 11.5 0, 1 1, 23 0
a 11.5, 11.5 0, 1 1, -23 0

你就會發現跟剛才講的貝茲曲線沒太大關係 😂,因為是圓形所以都是用橢圓弧表示 (a)。

範例簡化

前兩個指令都是 moveto,所以可以簡化成

M .5, 0
a 11.5, 11.5 0, 1 1, 23 0
a 11.5, 11.5 0, 1 1, -23 0

現在看懂了,可以做什麼?

  1. 實作 shape morphing 動畫,例如 Android 的 AnimatedVectorDrawable和 SVG animation,形狀之間變化,兩者指令數必須相同,因此先了解指令意義有助於順利製作向量圖動畫。
  2. 比起靜態檔案,你可以編寫程式動態產生曲線元素,例如 UI 裝飾等。幾乎各個平台都有繪製路徑的方式,用法也都類似,例如 MSDNApple Developer 等文件都有說明,甚至在 Unity 繪製三維曲線等。
  3. 動畫的 interpolator,例如常見的 ease-in、ease-out 等,也可以理解成時間對進度的一個曲線。例如在 CSS3,你可以用三次方貝茲曲線定義一個動畫的速度變化。
http://cubic-bezier.com/#0,.5,.5,1

以上是由 Dcard Android Team 帶來的第三篇技術內容,本系列預計介紹完 AnimatedVectorDrawable 以後結束,也許將來除了技術以外也可以提供更多生活化的內容,如果有感興趣的題材歡迎在底下留言建議,或者是寄信給我

By Dcard Android Team
Dcard 廣大徵才中唷!請到 👉🏼 https://join.dcard.today/

--

--