Android中矢量圖形的那些事 - SVG or Vector

之前對矢量圖形有所耳聞妄痪,但因?yàn)锳ndroid對于矢量圖形的原生支持較晚娄猫,所以一直沒好好研究過(16年2月25就出來的東西昏鹃,其實(shí)就是懶 =寡壮。=)贩疙。最近工作上正好遇到一個產(chǎn)品需求,想用SVG來解決况既,借此機(jī)會對SVG及Android對于矢量圖形的支持做了次了解这溅,當(dāng)然最后依然被SVG坑到,變成手寫XML來解決需求棒仍,不過這都是題外話了悲靴。

SVG是什么?

Scalable Vector Graphics(可縮放矢量圖形)是基于XML莫其,用于描述二維矢量圖形的圖形格式癞尚。SVG由W3C制定耸三,是一個開放標(biāo)準(zhǔn)。SVG本身允許包含3種圖形對象類型:

  1. 矢量圖形浇揩,包括矩形仪壮、圓、橢圓胳徽、多邊形积锅、直線、任意曲線等养盗。
  2. 嵌入外部圖像缚陷,包括png、jpeg往核、svg等箫爷。
  3. 文本。
    [from wikipedia]

以下是一個簡單的SVG格式示例:

<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
  <circle cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="red" />
  <path d="M150 0 L75 200 L225 200 Z" />
</svg>

SVG是通過標(biāo)簽的形式來描述圖形,比如<rect>矩形铆铆、<circle>圓形蝶缀、<polygon>多邊形等等普通標(biāo)簽,以及支持復(fù)雜的路徑的標(biāo)簽<path>.其中Path標(biāo)簽可以通俗的理解為是用命令的方式來控制畫筆薄货,比如:
** 將畫筆移動到指定坐標(biāo)位置 -> 畫一條直線到指定坐標(biāo)位置 -> 再畫一條曲線 -> 完成后抬起畫筆結(jié)束**

當(dāng)然Path標(biāo)簽也需要對應(yīng)的指令來完成操作,比如:
M150 0 L75 200 L225 200 Z

下面是Path支持的對應(yīng)指令:

M = moveto(M X,Y) :將畫筆移動到指定的坐標(biāo)位置
L = lineto(L X,Y) :畫直線到指定的坐標(biāo)位置
H = horizontal lineto(H X):畫水平線到指定的X坐標(biāo)位置
V = vertical lineto(V Y):畫垂直線到指定的Y坐標(biāo)位置
C = curveto(C X1,Y1,X2,Y2,ENDX,ENDY):三次貝賽曲線
S = smooth curveto(S X2,Y2,ENDX,ENDY)
Q = quadratic Belzier curve(Q X,Y,ENDX,ENDY):二次貝賽曲線
T = smooth quadratic Belzier curveto(T ENDX,ENDY):映射
A = elliptical Arc(A RX,RY,XROTATION,FLAG1,FLAG2,X,Y):弧線
Z = closepath():關(guān)閉路徑
注意:以上所有命令均允許小寫字母翁都。大寫表示絕對定位,小寫表示相對定位谅猾。

當(dāng)然柄慰,以上只是SVG中很小的一部分,還有其他很多強(qiáng)大的功能税娜。SVG本身已經(jīng)被廣泛使用坐搔,SVG矢量圖與位圖的差別,在于矢量圖可以盡可能的放大而不失真敬矩,并且同一張圖像概行,SVG的實(shí)現(xiàn)可能比png小很多。如果在精簡安裝包的時候弧岳,可以考慮部分圖標(biāo)改成矢量圖的方式凳忙。

Android中的矢量圖替身Vector

Android中對于矢量圖形的處理,并沒有選擇直接支持SVG文件禽炬,所以云端返回的svg格式圖片是無法直接被顯示的涧卵。
不過在Android 5.0中提出了矢量圖片的支持,叫做Vector腹尖。通過創(chuàng)建<vector>標(biāo)簽的xml元素來完成對矢量圖形的定義柳恐。

<!-- res/drawable/heart.xml -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    <!-- intrinsic size of the drawable -->
    android:height="256dp"
    android:width="256dp"
    <!-- size of the virtual canvas -->
    android:viewportWidth="32"
    android:viewportHeight="32">

  <!-- draw a path -->
  <path android:fillColor="#8fff"
      android:pathData="M20.5,9.5
                        c-1.955,0,-3.83,1.268,-4.5,3
                        c-0.67,-1.732,-2.547,-3,-4.5,-3
                        C8.957,9.5,7,11.432,7,14
                        c0,3.53,3.793,6.257,9,11.5
                        c5.207,-5.242,9,-7.97,9,-11.5
                        C25,11.432,23.043,9.5,20.5,9.5z" />
</vector>

Android Studio從1.4版本開始,包含了一個Vector Asset Studio的工具,可以選擇導(dǎo)入SVG或者PSD文件來幫助我們生成對應(yīng)的vector xml文件。
工具本身支持大多數(shù)主體元素乐设,但并不包含所有的SVG或PSD特性讼庇。SVG導(dǎo)入后的vector xml格式主體參考的是SVG中的pathdata語法,但虛線等屬性伤提、科學(xué)計數(shù)法巫俺、圖案填充(pattern)认烁、漸變(gradient)等特定標(biāo)簽是不支持的肿男。當(dāng)然Vector Asset Studio在我們導(dǎo)入的時候會有明確的提示哪些是被支持的、哪些是不被支持的却嗡。

以下兩種方法都可以打開Vector Asset Studio:
1. 對應(yīng)的drawable目錄上右鍵 -> New -> Vector Asset



2. File -> New -> Vector Asset


Android項目中如何使用Vector?

從Android 5.0開始舶沛,系統(tǒng)提供了兩個Api來完成對Vector的支持:

  1. VectorDrawable
  2. AnimatedVectorDrawable
    VectorDrawable負(fù)責(zé)矢量圖形的顯示,而AnimatedVectorDrawable負(fù)責(zé)基于矢量圖形的動畫效果窗价。

與此同時如庭,Android Support Library 23.2.0及之后的版本中,也加入了對Vector的向下兼容撼港,引入了VectorDrawableCompat和AnimatedVectorDrawableCompat坪它。

只需要引入對應(yīng)的AppCompat庫

compile 'com.android.support:appcompat-v7:23.2.0' 

VectorDrawable API 7+
AnimatedVectorDrawable API 11+

另外需要在 build.gradle 文件中新增如下配置:

//For Gradle Plugin 2.0+
 android {
   defaultConfig {
     vectorDrawables.useSupportLibrary = true
    }
 }
//For Gradle Plugin 1.5 or below
android {
  defaultConfig {
    // Stops the Gradle plugin’s automatic rasterization of vectors
    generatedDensities = []
  }
  // Flag notifies aapt to keep the attribute IDs around
  aaptOptions {
    additionalParameters "--no-version-vectors"
  }
}

如何使用VectorDrawable?

在布局文件中,我們可以針對ImageVIew帝牡、ImageButton等控制設(shè)置對應(yīng)的矢量圖片往毡。

如果用的Support包,那只需要通過app:srcCompat=“”屬性來替代以前的android:src即可靶溜。
另外記得添加xmlns:app="http://schemas.android.com/apk/res-auto"

<ImageButton
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  app:srcCompat="@drawable/ic_build_black_24dp"
  tools:layout_editor_absoluteX="11dp"
  tools:layout_editor_absoluteY="225dp"
  android:id="@+id/imageButton"
  android:tint="@color/colorAccent" />

如果使用的是Andorid5.0以上的原生支持开瞭,可以直接使用android:src=“”來完成對應(yīng)的展現(xiàn)。

如何使用AnimatedVectorDrawable罩息?

AnimatedVectorDrawable其實(shí)是針對Vector里面的各種元素嗤详,提供了屬性動畫的支持方式,從而完成對應(yīng)的動畫效果瓷炮。

借用官方文檔里的例子葱色,如果采用多個xml來實(shí)現(xiàn):
VectorDrawable's XML file: vd.xml

<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="vectorPath"
         android:fillColor="#000000"
         android:pathData="M300,70 l 0,-70 70,70 0,0 -70,70z" />
   </group>
</vector>

AnimatedVectorDrawable's XML file: avd.xml

<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
   android:drawable="@drawable/vd" >
     <target
         android:name="rotationGroup"
         android:animation="@anim/rotation" />
</animated-vector>

Animator XML file that is used in the AnimatedVectorDrawable's XML file: rotation.xml

<objectAnimator
   android:duration="6000"
   android:propertyName="rotation"
   android:valueFrom="0"
   android:valueTo="360" />

最后在布局中的使用方法,跟使用VectorDrawable是一樣的:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:id="@+id/imageview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:srcCompat="@drawable/avd"/>

</android.support.constraint.ConstraintLayout>

當(dāng)然到此為止還有最重要的一步娘香,否則看到的還只是靜態(tài)的矢量圖形:

ImageView demoView = (ImageView) findViewById(R.id.imageview);
        if(demoView.getDrawable() instanceof Animatable){
            ((Animatable) demoView.getDrawable()).start();
        }

上面是多xml的例子苍狰,相當(dāng)于矢量圖形、動畫目標(biāo)茅主、動畫規(guī)則是分開的舞痰。還有一種方式是用單一的xml文件來描述整個矢量動畫資源,需要Build Tools 版本在24及以上:

<?xml version="1.0" encoding="utf-8"?>
<animated-vector
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:aapt="http://schemas.android.com/aapt">
    <aapt:attr name="android:drawable">
        <vector xmlns:android="http://schemas.android.com/apk/res/android"
                android:width="64dp"
                android:height="64dp"
                android:viewportWidth="600"
                android:viewportHeight="600">
            <group
                android:name="rotationGroup"
                android:pivotX="300"
                android:pivotY="300"
                android:rotation="45.0" >
                <path
                    android:name="vectorPath"
                    android:fillColor="#000000"
                    android:pathData="M300,70 l 0,-70 70,70 0,0 -70,70z" />
            </group>
        </vector>
    </aapt:attr>
    <target android:name="rotationGroup">
        <aapt:attr name="android:animation">
            <objectAnimator
                android:propertyName="rotation"
                android:valueFrom="0"
                android:valueTo="360"
                android:duration="6000"
               />
        </aapt:attr>
    </target>
</animated-vector>

因?yàn)锳nimatedVectorDrawable改變的是vector中各元素的屬性值诀姚,所以極大的增添了動畫的實(shí)現(xiàn)手段及效果响牛。

不過坑依然有,當(dāng)API < 21時,擴(kuò)展包中的AnimatedVectorDrawableCompat會有一些限制:

Path Morphing (PathType evaluator) Used to morph one path into another path.

Path Interpolation Used to define a flexible interpolator (represented as a path) instead of the system-defined interpolators like LinearInterpolator.

Move along path The geometry object can move around, along an arbitrary path, as part of an animation.

在此限制下呀打,最能發(fā)揮效果的pathdata路徑動畫基本就可以忽略了矢赁。至少在發(fā)此文章的時候以上限制還在,只能默默期待以后吧贬丛。

總結(jié)

此文只是初略的講述了Android中矢量圖形的基礎(chǔ)使用方法撩银,當(dāng)然深入來講其實(shí)還有很多東西,包括第三方的一些SVG庫豺憔、矢量動畫的一些高級用法等等额获。在此只是做一個用法的基本記錄,同時希望也是借此機(jī)會拋磚引玉恭应,給大家提供一個新的處理思路吧抄邀。

原文鏈接: Android中矢量圖形的那些事 - SVG or Vector

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市昼榛,隨后出現(xiàn)的幾起案子境肾,更是在濱河造成了極大的恐慌,老刑警劉巖胆屿,帶你破解...
    沈念sama閱讀 222,627評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件奥喻,死亡現(xiàn)場離奇詭異,居然都是意外死亡非迹,警方通過查閱死者的電腦和手機(jī)环鲤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,180評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來彻秆,“玉大人楔绞,你說我怎么就攤上這事〈蕉遥” “怎么了酒朵?”我有些...
    開封第一講書人閱讀 169,346評論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長扎附。 經(jīng)常有香客問我蔫耽,道長,這世上最難降的妖魔是什么留夜? 我笑而不...
    開封第一講書人閱讀 60,097評論 1 300
  • 正文 為了忘掉前任匙铡,我火速辦了婚禮,結(jié)果婚禮上碍粥,老公的妹妹穿的比我還像新娘鳖眼。我一直安慰自己,他們只是感情好嚼摩,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,100評論 6 398
  • 文/花漫 我一把揭開白布钦讳。 她就那樣靜靜地躺著矿瘦,像睡著了一般。 火紅的嫁衣襯著肌膚如雪愿卒。 梳的紋絲不亂的頭發(fā)上缚去,一...
    開封第一講書人閱讀 52,696評論 1 312
  • 那天,我揣著相機(jī)與錄音琼开,去河邊找鬼易结。 笑死,一個胖子當(dāng)著我的面吹牛柜候,可吹牛的內(nèi)容都是我干的搞动。 我是一名探鬼主播,決...
    沈念sama閱讀 41,165評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼改橘,長吁一口氣:“原來是場噩夢啊……” “哼滋尉!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起飞主,我...
    開封第一講書人閱讀 40,108評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎高诺,沒想到半個月后碌识,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,646評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡虱而,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,709評論 3 342
  • 正文 我和宋清朗相戀三年筏餐,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片牡拇。...
    茶點(diǎn)故事閱讀 40,861評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡魁瞪,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出惠呼,到底是詐尸還是另有隱情导俘,我是刑警寧澤,帶...
    沈念sama閱讀 36,527評論 5 351
  • 正文 年R本政府宣布剔蹋,位于F島的核電站旅薄,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏泣崩。R本人自食惡果不足惜少梁,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,196評論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望矫付。 院中可真熱鬧凯沪,春花似錦、人聲如沸买优。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,698評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至身笤,卻和暖如春豹悬,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背液荸。 一陣腳步聲響...
    開封第一講書人閱讀 33,804評論 1 274
  • 我被黑心中介騙來泰國打工瞻佛, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人娇钱。 一個月前我還...
    沈念sama閱讀 49,287評論 3 379
  • 正文 我出身青樓伤柄,卻偏偏與公主長得像,于是被迫代替她去往敵國和親文搂。 傳聞我的和親對象是個殘疾皇子适刀,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,860評論 2 361

推薦閱讀更多精彩內(nèi)容