Android 矢量圖詳解

官方文檔

關於 Vector,在官方開發指南中介紹。本文章是由個人翻譯官方指南然後添加個人理解完成。

由於個人精力有限,多個渠道發佈,排版上可能會有問題,如果影響查看,請移步 Android 開發者家園

Vector Drawables 概述

VectorDrawable 和 AnimatedVectorDrawable 是在 Android 5.0 系統中第一次加入,當然我們可以使用 Android 的支持庫,來支持舊的版本,通過 VectorDrawableCompat 和 AnimateVectorDrawableCompat 來實現。

VectorDrawble 是在 xml 文件中定義的矢量圖形。xml 文件中定義的矢量圖形,它是一組帶有顏色信息的點、線和曲線,使用矢量圖主要的優點是圖形可伸縮性。可以在不損失顯示質量的情況下進行縮放,這意味著我們可以在不同的屏幕密度的手機上使用相同的文件。這樣會使 APK 文件變小更加有利於開發人員維護。我們還可以通過多個 XML 文件和矢量圖結合用於動畫。

既然說起 VectorDrawable 了,那就不得不提 SVG (Scalable Vector Graphic)了,這兩個經常混淆,其實 SVG 就是一種基於可擴展語言(xml),用於描述二維矢量圖形的一種圖形格式(和我們常見的 .png 等等圖片一樣,都是一種圖片格式),它有自己的一套編寫規範(使用 XML 編寫的),所以這種圖片是根據他自己的一套規範通過 XML 語言編寫而成的圖片。而我們的 VectorDrawable 是編程中的,它僅支持 SVG 規範中有限的內容。Android Studio 支持將 SVG 文件轉換成 VectorDrawable 。這就是他們兩者的關係。

path 中的常用的簡單繪製命令

  • moveto 命令 M 移動到新的位置
  • closepath 命令 Z 封閉路徑,從當前的位置畫一條直線到該路徑或者子路徑起始位置
  • lineto 命令 L ,從當前的位置畫一條線到指定的位置
  • horizontal lineto 命令 H 水平畫一條直線到指定位置
  • vertical lineto 命令 V 垂直畫一條直線到指定位置
  • 貝塞爾曲線 命令 Q
  • 光滑二次貝塞爾曲線 命令 T
  • elliptical arc 命令 A 橢圓弧

每個命令都有大小寫的形式,大寫代表後面的參數是絕對座標,小寫表示相對座標(我們一般用大寫就可以了),參數之間用空格或者逗號隔開。所謂的相對座標是相對於前面一個點的,比如:M30,0 l 10,10 換算成絕對座標就是 M30,0 L40,10

命令使用實例

  • M(x y) 移動到座標 x,y 處
  • Z 後面不接參數,直接連接起點和終點
  • L(x y)直線連接到座標 x,y 處
  • H(x) 水平連接
  • V(y) 垂直連接
  • C(x1 y1 x2 y2 x y)控制點 x1,y1 x2,y2 終點座標 x,y
  • Q(x1 y1 x y)控制帶點 x1,y1 終點座標 x ,y;
  • A(rx,ry,x-axis-rotation,large-arc-flag,sweep-flag,x,y);
  • rx,ry 橢圓半徑
  • x-axis-rotation x 軸旋轉角度
  • large-arc-flag 為 0 的時候表示取小弧度,1 的時候取大弧度
  • sweep-flag 0 取逆時針方向,1 取順時針方向
  • (x,y) 是終點的座標

VectorDrawable 如何定義

VectorDrawable 在 drawable 文件夾中通過 <vector> 來定義,這裡先來詳細的介紹一下 vector 中的各個屬性(和網上的許多不一樣,網上的大多都沒有自己驗證過)/<vector>


<vector> android:name(用於定義這個 vector drawable 的名字)、
android:width(定義該 drawble 的內部寬度,支持所有的 Android 系統支持的尺寸單位,通常使用 dp)
android:height(定義該 drawble 的內部高度,支持所有的 Android 系統支持的尺寸單位,通常使用 dp)
android:viewportWidth(定義矢量圖視圖的寬度,實際上就是對應 path 路徑所使用的數據)
android:viewportHeight(定義矢量圖視圖的高度,實際上就是對應 path 路徑所使用的數據)
android:tint(定義該 drawble 線條的顏色,定義了後,你再在路徑裡面設置顏色就沒有作用了)
android:tintMode(定義 tint 顏色的 Porter-Duff blending 模式,默認值為 src_in,暫時不用理會)
android:autoMirrored 設置當系統為 RTL (right-to-left)佈局的時候,是否自動鏡像該圖片。
android:alpha 該圖片的透明屬性
>
<grup> // 有時候我們需要對幾個路徑一起處理,這樣就可以使用 group 元素來把多個 path 放到一起,group 支持的屬性有
android:name 定義 group 的名字
android:rotation 定義該 group 的路徑旋轉多少度(順時針旋轉)
android:pivotX 定義縮放和旋轉該 group 時候的 X 參考點。該值相對於 vector 的 viewport 值來指定的。
android:pivotY 定義縮放和旋轉該 group 時候的 Y 參考點。該值相對於 vector 的 viewport 值來指定的。

android:scaleX 定義 X 軸的縮放倍數
android:scaleY 定義 Y 軸的縮放倍數
android:translateX 定義移動 X 軸的位移。相對於 vector 的 viewport 值來指定的
android:translateY 定義移動 Y 軸的位移。相對於 vector 的 viewport 值來指定的>
<path> // path 元素裡面的 pathData 就是矢量圖的路徑數據,除此之外還可以設置其他的屬性。path 的屬性有:
android:name 定義該 path 的名字,這樣在其他地方可以通過名字來引用這個路徑
android:pathData 和 SVG 中 d 元素一樣的路徑信息
android:fillColor 定義填充路徑的顏色,如果沒有定義則不填充路徑
android:strokeWidth 定義路徑邊框的粗細尺寸
android:strokeAlpha 定義路徑邊框的透明度
android:fillAlpha 定義填充路徑顏色的透明度
android:trimPathStart 從路徑起始位置(path 的 M 位置)截取後剩下的內容,取值範圍從 0 到 1,比如,取值是 0.3 則截取後的內容就是 原長度 - (原長度*0.3)
android:trimPathEnd 從路徑起始位置位置截取的內容,取值範圍從 0 到 1,比如,取值是 0.3,則截取後的內容就是 原長度*0.3
需要注意的是如果 trimPathStart 和 strimPathEnd 一塊使用的話,這裡有個規律如果 trimPathEnd 取值大於等於 trimPathStart 的時候結果就是他們兩者分別截取後內容的交集,如果 trimPathEnd 小於 trimPathStart 的時候,取值就是他們倆的合集(這是經過我無數的實驗得出的規律,你也可以嘗試一下)

android:trimPathOffset 其實就是設置開始點的偏移位置(取值 從 0 到 1)1 的話就是開始點和結束的互換了,注意這個路徑是可以循環的(下面畫圖說明)
android:strokeLineCap 設置路徑的線頭的形狀,取值為 butt,round,square 默認是 butt
android:strokeLineJoin 設置路徑交界處的連接方式,取值為 miter、round、bevel 默認是 miter
android:strokeMiterLimit 設置斜角的上界 默認是 4 (當 strokeLineJoin 設置為 "miter" 的時候,繪製兩條線段以銳角相交的時候,所得的斜面可能相當長,當斜面太長,就會變的不協調。strokeMiterLimit 屬性為斜面的長度設置了一個上限。這個屬性表示斜面長度和線條長度的比值。當 strokeLineJoin 設置為其他屬性時,這個屬性是無效的)

/<path>

vector 還支持 clip-path 元素,定義當前繪製的剪切路徑。注意:clip-path 只對當前的 group 和子 group 有效。需要 API 大於等於 21








/<grup>
/<vector>


Android 矢量圖詳解


offset說明.png

矢量動畫

利用 XML 文件來設置矢量動畫

  1. 創建一個矢量圖

<vector> android:width="200dp"
android:height="200dp"
android:viewportWidth="100"
android:viewportHeight="100">
<group>
<path> android:fillColor="@color/colorPrimary"
android:name="head"
android:pathData=" M50,50 A15,15,0,1,1 50,51Z"
android:strokeWidth="2"
android:strokeColor="@color/colorPrimary"/>
<group>
<path> android:name="eye_left"
android:pathData="M55,40A2,2,0,1,1,55,41"/>
<path> android:name="eye_right"
android:pathData="M69,40A2,2,0,1,1,69,41"/>
/<path>/<path>/<group>
<path> android:pathData="M60,55L55,60H65Z"/>
/<path>/<path>/<group>
/<vector>


Android 矢量圖詳解


head.png

哈哈,樣子太醜了,大家就湊合著看把。

  1. 在 drawble 創建矢量動畫
  2. 目的就是將我們的矢量圖和 objectAnimator 關聯起來

<animated-vector> // 對應動畫文件
android:drawable="@drawable/vector_simple">
<target> android:animation="@animator/head"
// 這裡的名字對應你的矢量圖中想要產生動畫的 path 或者 group 或者 clip-path 的名字
android:name="head_eyes"/>
/<target>/<animated-vector>
  1. 在 animator 中創建動畫


<objectanimator> android:duration="200"
android:propertyName="translateY"
android:repeatCount="infinite"
android:repeatMode="reverse"
android:valueFrom="0"
android:valueTo="20"
android:valueType="floatType"/>
/<objectanimator>

  1. 佈局文件中添加圖片
<imageview> android:id="@+id/iv_android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:class="lazy" data-original="@drawable/animated_head"
android:contentDescription="@string/app_name"/>
/<imageview>
  1. 在程序中啟動動畫
Drawable drawable = ivAndroid.getDrawable();
((Animatable)drawable).start();

效果圖


Android 矢量圖詳解


效果圖.gif

在 objectAnimator 的 propertyName 中有兩個很重要的屬性值,trimPathEndtrimPathStart 表示截取,和前面介紹的 path 裡面的類似,利用這個可以繪製 vectordrawble。注意如果動畫使用這個兩個屬性值的話,animated-vector 中 target 對應的 name 必須是 path 類型不能是 group 效果圖:


Android 矢量圖詳解


trimPathStart.gif

SVG 圖片轉成 vectordrawble

利用我們 Android Studio 提供的工具就可以將 SVG 格式的圖片直接轉成我們的 vectordrawble 了。


Android 矢量圖詳解


svgtovector.png

Android 矢量圖詳解


選擇圖片.png


分享到:


相關文章: