Android SVG矢量資源的使用方法

VectorDrawable 與 SVG

Android 5.0(Lollipop, API 21)後,新增了<vector>標籤,以VectorDrawable的形式支持SVG類型矢量圖形(SVG本質爲XML標記描述的圖形)。
※ Android不直接支持SVG圖形文件html

SVG文件(XML)對應的VectorDrawable資源封裝格式爲:android

<vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="64dp"
     android:width="64dp"
     android:viewportHeight="600"
     android:viewportWidth="600" >
     <group
         android:name="rotationGroup"
         android:pivotX="300.0"
         android:pivotY="300.0"
         android:rotation="45.0" >
         <path
             android:name="v"
             android:fillColor="#000000"
             android:pathData="M300,70 l 0,-70 70,70 0,0 -70,70z" />
     </group>
 </vector>

※ 一般由SVG文件轉換爲VectorDrawable,而非手工錄入git

  1. <vector> 是 VectorDrawable 對應的根標籤
  2. android:widthandroid:height對應矢量圖的實際參考尺寸(實際可根據容器尺寸無損縮放,但此值將做爲容器(ImageView)的 wrap_content 參考尺寸),基於加載性能考慮,Google推薦限定在 200x200dp 之內,通常與下面的viewportWidthviewportHeight成比例定義
  3. android:viewportWidthandroid:viewportHeight是指當前Drawable對應的Canvas的大小,用於爲<path/>標籤中的路徑數據提供繪製位置的參考座標系及繪製範圍
  4. <path/>標籤對應路徑信息, 這裏的path與咱們自定義繪製圖形時用的Path原理同樣, 就是記錄一些繪圖操做, 具體對應其中的 pathData。
  5. android:fillColor爲默認黑色(#FF000000)時,在View容器內將使用tint顏色取代,不然將呈現爲android:fillColortint的混合顏色。

<path/>路徑的路徑描述指令含義表:github

M = moveto 至關於 android Path 裏的moveTo(),用於移動起始點 
L = lineto 至關於 android Path 裏的lineTo(),用於畫線 
H = horizontal lineto 用於畫水平線 
V = vertical lineto 用於畫豎直線 
C = curveto 至關於cubicTo(),三次貝塞爾曲線 
S = smooth curveto 一樣三次貝塞爾曲線,更平滑 
Q = quadratic Belzier curve quadTo(),二次貝塞爾曲線 
T = smooth quadratic Belzier curveto 一樣二次貝塞爾曲線,更平滑 
A = elliptical Arc 至關於arcTo(),用於畫弧 
Z = closepath 至關於closeTo(),關閉path

大寫表明絕對位置, 小寫表明相對位置

官方標準定義細則參考:SVG Paths Definition - W3C算法

SVG圖標平臺

【Iconfont】阿里媽媽矢量圖標平臺api

SVG編輯軟件

Inkscape
跨平臺開源矢量圖形編輯軟件,免費 + 三平臺通用,支持直接編輯XML數據
相似的軟件還有Illustrator、CorelDraw等app


SVG 轉 VectorDrawable

※ 初始化VectorDrawable將消耗更多CPU資源,Google推薦將矢量圖最大尺寸限定在 200x200dp 之內ide


VectorDrawable 向後兼容

對於Android 5.0以前的設備,有兩種方式兼容VectorDrawable資源:svg

1. 利用 Vector Asset Studio 工具動態生成位圖

Android Studio 內置一個名爲 Vector Asset Studio 的工具,在低版本SDK上編譯APK期間,針對VectorDrawable腳本自動生成一組PNG位圖資源BitmapDrawable,取代矢量圖形(在5.0及之後的手機上運行時會正常引用VectorDrawable)。工具

須要配置build.gradle

defaultConfig {
    vectorDrawables.generatedDensities = ['hdpi','xxhdpi']
}

自動生成PNG時,所支持的VectorDrawable元素子集

2. 添加 Support Library 23.2+ 兼容包

Support Library 23.2+ 包中包含VectorDrawableCompatAnimatedVectorDrawableCompat兼容類,用於代碼中橋接爲BitmapDrawable及其動畫支持,其中Drawable最低SDK爲Android 2.1,動畫最低SDK爲Android 3.0

※ 兼容包要求使用Gradle 2.0或以上版本,而且不支持VectorDrawable嵌套引用,不支持直接解析爲VectorDrawable類型,也再也不編譯期生成PNG位圖

build.gradle配置以下:

android {
  defaultConfig {
    vectorDrawables.useSupportLibrary = true
  }
}

dependencies {
  compile 'com.android.support:appcompat-v7:23.2.0'
}

兼容包在矢量資源引用、代碼調用時,存在必定限制

  • 在 ImageView 等引用 VectorDrawable 資源時,須要使用app:srcCompat取代android:src
  • 代碼中使用setImageResource()指定資源 id 時,無需更改代碼
  • 將 VectorDrawable 用於 View 背景時,須要經過如下代碼設定:
Resources resources = context.getResources(Resources, int, Theme);
Theme theme = context.getTheme();
Drawable drawable = VectorDrawableCompat.create(resources, R.drawable.vector_drawable, theme);
view.setBackground(drawable);

代碼中須要進行Drawable的實現類型轉換時,可以使用如下代碼段執行:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
   VectorDrawable vectorDrawable =  (VectorDrawable) drawable;
} else {
   BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
}

矢量動畫

使用矢量圖可進行特殊的動畫繪製,如形態變換、動態繪圖等。

主要步驟

定義矢量資源及其關聯動畫 XML 腳本

  1. 建立矢量圖形資源VectorDrawable,並在須要動畫特效的子元素上使用屬性android:name給定任意動畫對象名
  2. 建立Animator屬性動畫腳本,可以使用ObjectAnimatorAnimatorSet,對VectorDrawable的特定元素屬性進行動畫控制
  3. 建立AnimatedVectorDrawable,做用是鏈接VectorDrawableAnimator,組合爲單一動畫型Drawable對象
  4. 建立好的AnimatedVectorDrawable不能直接用於 ImageView,須要經過代碼設定,並顯式開始執行動畫
官方文檔

在線實時輸出 XML 腳本

Google工程師開發的開源項目 AndroidIconAnimator,可實如今線實時構造、編輯、預覽 VectorDrawable 動畫,並導出XML腳本,使用教程可參考 Qiita帖子

代碼設置

建立好的 VectorDrawable 動畫資源,須要經過代碼方式加載到 View 容器內,並指定執行動畫

使用原生支持的代碼設定(5.0 LOLLIPOP, API 21)

ImageView imageView = (ImageView) findViewById(R.id.imageView);
AnimatedVectorDrawable vectorDrawable = (AnimatedVectorDrawable) getResources().getDrawable(AnimatedVectorDrawableRes, Theme);
imageView.setImageDrawable(vectorDrawable);
vectorDrawable.start();

使用 Support Library 時的動畫設置

矢量動畫要求最低SDK爲Android 3.0,而且不支持<path>路徑類型的變換

ImageView imageView = (ImageView) findViewById(R.id.imageView);
AnimatedVectorDrawableCompat drawableCompat = AnimatedVectorDrawableCompat.create(context, AnimatedVectorDrawableRes);
imageView.setImageDrawable(drawableCompat);
drawableCompat.start();

特別介紹幾個特殊屬性:

  • <group>元素:
    • rotation:旋轉角度,取值爲360角度,valueType=floatType
    • pivotX / pivotY:旋轉中心座標,以viewport爲參照基準
  • <path>元素:
    • pathData:矢量圖形的繪製路徑數據位點,可動畫形變爲另外一種圖案,要求動畫參數值必須擁有相同長度參數及一致的路徑描述指令,而且 ObjectAnimator 中android:valueType="pathType"(Support 包不支持該數據進行變換動畫)
    • trimPathStart:從路徑起始點開始向後裁剪(擦除)的相對距離,取值 [0, 1],,0 表示路徑起始點,1 表示路徑結束點,可實現逐步消退、繪製動效,android:valueType="floatType"
    • trimPathEnd:從路徑結束點開始向前裁剪的相對距離,取值 [0, 1],0 表示路徑起始點,1 表示路徑結束點
    • trimPathOffset:從路徑起始、結束點開始裁剪的相對距離,取值 [0, 1],0 表示不裁剪,1 表示該路徑徹底不繪製
  • <clip-path>元素:遮罩路徑、反蒙版路徑,該路徑範圍內的元素纔會真正進行繪製,做用於當前所在的<group>內定義在其後面的全部<path>元素
    • pathData:定義遮罩路徑,動畫操做方式與<path>相同

pathData 形變更畫參考

已知bug:

  • <animated-vector>標籤在使用時會發生錯誤警告requires API level 21,不影響兼容包的編譯運行
  • 放置於animator目錄內的Animator腳本,須要在<animated-vector><target>中手工引用@animator/資源id(自動提示補全菜單失效)
  • 使用動畫時,ImageView 不能使用android:tint屬性,不然會致使Mutate() is not supported for older platform異常崩潰
  • 經過 AAPT 標籤使用單一腳本混合定義時,Android Studio 會出現識別錯誤提示
  • 矢量動畫經過關聯 Property Animation 打包爲 Drawable 方式實現,對屬性的動態修改將影響全部同一 Drawable 資源產生的對象(Drawable 狀態共享機制),而且兼容包不支持 mutate() 調用(狀態分離,兼容包內要求API 23以上),實際上代碼暫時沒法訪問矢量元素內部屬性(如 pathData 等)

其餘參考文獻及工具連接集合:

首發地址在 簡書

相關文章
相關標籤/搜索