前言
矢量圖也稱(chēng)為面向?qū)ο蟮膱D像或繪圖圖像槐壳,是根據(jù)幾何特性來(lái)繪制的圖形,在安卓開(kāi)發(fā)中可以使用失量圖代替原來(lái)的圖片資源,矢量圖具有占用空間小和可以隨意縮放但不失真的優(yōu)勢(shì)吨拗,在我的多個(gè)項(xiàng)目中都有運(yùn)用。
通過(guò)學(xué)習(xí)和實(shí)踐跟伏,我總結(jié)了一些與矢量圖相關(guān)的知識(shí)丢胚,方便今后更好的使用矢量圖,同時(shí)也可以供大家查閱參考受扳。
矢量圖的繪制
繪制矢量圖之前需要先定義畫(huà)布的寬高携龟,后續(xù)的繪制效果都展示在這個(gè)畫(huà)布上。在繪制過(guò)程中需要輸入的坐標(biāo)就是這個(gè)畫(huà)布上的點(diǎn)勘高。
安卓的矢量圖常見(jiàn)于drawable
文件夾下峡蟋,是一個(gè)xml文件坟桅,由vector
標(biāo)簽包裹,在vector
標(biāo)簽中可包含多個(gè)path
標(biāo)簽蕊蝗,依次疊加顯示仅乓。
vector標(biāo)簽的常用屬性:
android:width="200dp"
- 預(yù)覽寬度
android:height="200dp"
- 預(yù)覽高度
android:viewportWidth="1024"
- 畫(huà)布寬度(下面path路徑中的點(diǎn)位位于畫(huà)布中)
android:viewportHeight="1024"
- 畫(huà)布高度
android:tint="#FFFFFF"
- 矢量圖著色(會(huì)對(duì)矢量圖的全部?jī)?nèi)容進(jìn)行統(tǒng)一著色,覆蓋原有顏色)
path標(biāo)簽的常用屬性
android:fillColor="#FFFFFF"
- 填充顏色
android:pathData="M82,500H942V524H82V500"
- 矢量圖路徑
android:strokeColor="#FFFFFF"
- 邊框顏色蓬戚,默認(rèn)的邊框是透明的
android:strokeWidth="20"
- 邊框的寬度
在矢量圖中最重要的就是path
屬性夸楣,圖像的樣式就是由path
屬性中的數(shù)據(jù)繪制而成,這些數(shù)據(jù)由不同的命令組合而成子漩,下面就介紹一些矢量圖的繪制命令豫喧。
- M 設(shè)置畫(huà)筆的位置,語(yǔ)法:M坐標(biāo)
M200,10
- 將畫(huà)筆移動(dòng)到200,10的位置幢泼。 - L 從當(dāng)前位置連接一條直線(xiàn)至指定位置紧显,語(yǔ)法:L坐標(biāo)
L300,100
- 從當(dāng)前位置連接一條直線(xiàn)到300,100位置。 - H 保持縱坐標(biāo)不變缕棵,畫(huà)一條橫線(xiàn)至目標(biāo)橫坐標(biāo)位置孵班,語(yǔ)法:H橫坐標(biāo)
H200
- 畫(huà)一條橫線(xiàn)至橫坐標(biāo)為200的點(diǎn)上。 - V 保持橫坐標(biāo)不變招驴,畫(huà)一條豎線(xiàn)至目標(biāo)縱坐標(biāo)位置篙程,語(yǔ)法:V縱坐標(biāo)
V200
- 畫(huà)一條豎線(xiàn)至縱坐標(biāo)為200的點(diǎn)上。 - Q 連接目標(biāo)點(diǎn)位并對(duì)連線(xiàn)做二次貝塞爾曲線(xiàn)處理忽匈,語(yǔ)法:Q貝塞爾坐標(biāo)房午,目標(biāo)點(diǎn)坐標(biāo)
Q300,100,400,200
- 連接當(dāng)前位置和400,200做一條直線(xiàn),在直線(xiàn)上做貝塞爾曲線(xiàn)變換丹允,變換的錨點(diǎn)為300,100郭厌。 - C 連接目標(biāo)點(diǎn)位并對(duì)連線(xiàn)做三次貝塞爾曲線(xiàn)處理,語(yǔ)法:C貝塞爾坐標(biāo)1雕蔽,貝塞爾坐標(biāo)2折柠,目標(biāo)點(diǎn)坐標(biāo)
C300,250,500,350,400,400
- 連接當(dāng)前位置和400,400做一條直線(xiàn),先用貝塞爾坐標(biāo)1對(duì)直線(xiàn)做一次變換批狐,再用貝塞爾坐標(biāo)2對(duì)之前的結(jié)果做一次變換扇售,最終會(huì)得到一個(gè)S型的線(xiàn)段。 - A 連接起始點(diǎn)與目標(biāo)點(diǎn)嚣艇,再根據(jù)指定的半徑和角度繪制一個(gè)圓承冰,使線(xiàn)段的兩個(gè)端點(diǎn)都在圓的邊上,然后根據(jù)圓弧參數(shù)和繪制方向參數(shù)畫(huà)出所需的圓弧食零,語(yǔ)法:A橫向半徑困乒,縱向半徑,旋轉(zhuǎn)角度贰谣,圓弧大小娜搂,繪制方向迁霎,目標(biāo)坐標(biāo)
A500,300,0,0,1,0,400
- 繪制圓弧的過(guò)程比較復(fù)雜,下面分步模擬一下百宇。- 根據(jù)所指定的橫向半徑和縱向半徑先繪制一個(gè)橢圓考廉,如果兩個(gè)半徑一致就是一個(gè)正圓。
- 根據(jù)指定的旋轉(zhuǎn)角度對(duì)剛剛繪制的橢圓進(jìn)行旋轉(zhuǎn)携御,所傳入的角度與0-360度一一對(duì)應(yīng)昌粤,0=沒(méi)有旋轉(zhuǎn),90=把橢圓豎過(guò)來(lái)因痛,360=轉(zhuǎn)了一整圈婚苹,720=轉(zhuǎn)了兩圈岸更。
- 此時(shí)一個(gè)目標(biāo)橢圓已經(jīng)形成鸵膏,然后需要用起點(diǎn)和終點(diǎn)連成線(xiàn)段去切割這個(gè)橢圓,使起點(diǎn)和終點(diǎn)恰好都在橢圓的邊上怎炊,如果橢圓很小谭企,會(huì)將橢圓等比放大至兩點(diǎn)位置。
- 在上一步中有兩種情況评肆,一個(gè)是橢圓比較小债查,放大后兩點(diǎn)連線(xiàn)為橢圓的直徑,這時(shí)圓弧大小的參數(shù)就沒(méi)用了瓜挽,寫(xiě)1或0都行盹廷。如果橢圓比較大,那么符合兩點(diǎn)都在橢圓邊上情況的位置就有兩個(gè)久橙,此時(shí)如果從起點(diǎn)到終點(diǎn)順時(shí)針去畫(huà)圓弧就會(huì)有一個(gè)大圓弧一個(gè)小圓弧俄占,如果我們需要大圓弧的情況就把圓弧大小的參數(shù)設(shè)置為1,反之則設(shè)置為0淆衷。
- 接下來(lái)的一個(gè)參數(shù)是繪制順序缸榄,繪制順序?yàn)?的時(shí)候是順時(shí)針繪制,繪制順序?yàn)?的時(shí)候是逆時(shí)針繪制祝拯,一般我們都會(huì)先根據(jù)圖像的需求指定繪制順序甚带,再根據(jù)繪制順序指定圓弧大小參數(shù)。
- 最后的一個(gè)參數(shù)是目標(biāo)坐標(biāo)佳头,這個(gè)坐標(biāo)在第三步的時(shí)候已經(jīng)使用了鹰贵,此時(shí)我們需要的圓弧就已經(jīng)畫(huà)完了。
- Z 閉合圖形康嘉,將當(dāng)前位置與路徑起始點(diǎn)連接起來(lái)
將前面的命令示例連接起來(lái)就可以生成一個(gè)完整的圖像碉输,它大概長(zhǎng)這個(gè)樣子:
畫(huà)布的尺寸為500x500,圖上的頂點(diǎn)是200,10的位置凄鼻,也是我們開(kāi)始作圖的起點(diǎn)腊瑟。通過(guò)這個(gè)圖片可以更好的理解每一個(gè)繪圖命令聚假。
以上的繪制命令均有其對(duì)應(yīng)的小寫(xiě)版本,
M-m L-l H-h V-v Q-q C-c A-a
闰非,小寫(xiě)版本的功能與大寫(xiě)版本一致膘格,但其中的坐標(biāo)都替換成了相對(duì)位置,使用相對(duì)位置的好處是起點(diǎn)發(fā)生變化后财松,后面的路徑自動(dòng)跟隨起點(diǎn)移動(dòng)瘪贱,不需要所有的路徑都調(diào)整參數(shù)。安卓矢量圖的路徑會(huì)自動(dòng)閉合辆毡,結(jié)尾沒(méi)有加Z命令也和添加了Z命令的效果一致菜秦。
矢量圖動(dòng)畫(huà)
安卓中可以為矢量圖添加動(dòng)畫(huà)效果,這樣用戶(hù)就可以看到一個(gè)動(dòng)的圖片舶掖,可以一定程度的提高app的交互效果球昨。矢量圖動(dòng)畫(huà)是圖形內(nèi)部的變化,可以做到View動(dòng)畫(huà)無(wú)法實(shí)現(xiàn)的效果眨攘。
pathData動(dòng)畫(huà)
這種動(dòng)畫(huà)針對(duì)的是矢量圖中path
字段的值主慰,通過(guò)連續(xù)改變path
字段的值而達(dá)到產(chǎn)生動(dòng)畫(huà)的效果。
注:pathData動(dòng)畫(huà)所需的AnimatedVectorDrawable最低要求API等級(jí)為25
實(shí)現(xiàn)一個(gè)矢量圖動(dòng)畫(huà)需要以下幾步:
1. 準(zhǔn)備起始狀態(tài)和結(jié)束狀態(tài)的矢量圖兩張鲫售。
2. 創(chuàng)建動(dòng)畫(huà)配置文件共螺。
3. 創(chuàng)建動(dòng)畫(huà)矢量圖文件。
4. 啟動(dòng)動(dòng)畫(huà)情竹。
- 首先藐不,我們準(zhǔn)備用于動(dòng)畫(huà)的兩張矢量圖,分別代表動(dòng)畫(huà)的起始樣式和結(jié)束樣式秦效,而且這兩張圖執(zhí)行動(dòng)畫(huà)的path必須是同形path雏蛮。
通過(guò)對(duì)矢量圖繪制的了解,我們知道矢量圖就是一個(gè)一個(gè)的點(diǎn)位進(jìn)行直線(xiàn)或曲線(xiàn)連接形成的一個(gè)圖形棉安,所以在做矢量圖變化的時(shí)候底扳,系統(tǒng)是把我們初始各個(gè)點(diǎn)位的坐標(biāo)通過(guò)系統(tǒng)計(jì)算后逐漸的改變成了結(jié)束時(shí)的坐標(biāo),這就要求我們做動(dòng)畫(huà)的兩個(gè)矢量圖點(diǎn)位的個(gè)數(shù)是一致的贡耽,同時(shí)由于系統(tǒng)比較傻衷模,只能是直線(xiàn)轉(zhuǎn)直線(xiàn),曲線(xiàn)轉(zhuǎn)曲線(xiàn)蒲赂,所以這兩張圖的路徑命令及順序也要一致阱冶。這就是傳說(shuō)中的同形path。
基于這種要求滥嘴,我準(zhǔn)備了兩個(gè)矢量圖:
// icon_filter_off.xml 未啟用篩選功能時(shí)的樣式
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="200dp"
android:height="200dp"
android:tint="#000000"
android:viewportWidth="1024"
android:viewportHeight="1024">
<path
android:fillColor="#000000"
android:pathData="M102,112L282,382V912Q282,942,322,912L482,792V382L812,100Q832,82,812,82H122Q82,82,102,112" />
<path
android:name="status"
android:fillColor="#000000"
android:pathData="M582,490L582,530L882,530L882,490ZM582,640L582,680L882,680L882,640ZM582,790L582,830L882,830L882,790Z" />
</vector>
// icon_filter_on.xml 啟用了篩選功能時(shí)的樣式
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="200dp"
android:height="200dp"
android:tint="#000000"
android:viewportWidth="1024"
android:viewportHeight="1024">
<path
android:fillColor="#000000"
android:pathData="M102,112L282,382V912Q282,942,322,912L482,792V382L812,100Q832,82,812,82H122Q82,82,102,112" />
<path
android:name="status"
android:fillColor="#000000"
android:pathData="M592,670L562,700L662,800L692,770ZM662,800L692,830L792,730L762,700ZM762,700L792,730L892,630L862,600Z" />
</vector>
我的目標(biāo)是在狀態(tài)切換時(shí)把右下角的小圖標(biāo)做一個(gè)動(dòng)畫(huà)轉(zhuǎn)換木蹬,所以右下角的路徑是單獨(dú)寫(xiě)了一個(gè)path,同時(shí)把path命名為status若皱。
這兩個(gè)矢量圖是我通過(guò)代碼敲出來(lái)的镊叁,也滿(mǎn)足了同形path的要求尘颓,為了這兩個(gè)矢量圖,我把小學(xué)和初中的數(shù)學(xué)知識(shí)又都搬了出來(lái)晦譬,一通計(jì)算疤苹,才算出了這些坐標(biāo),可惜還是沒(méi)能達(dá)到我的心理預(yù)期敛腌,只能先湊合用卧土。
- 接下來(lái)開(kāi)始創(chuàng)建動(dòng)畫(huà)配置。
在res\animator
文件夾下創(chuàng)建filter_turn_on.xml
文件像樊,代碼如下:
// filter_turn_on.xml 動(dòng)畫(huà)的配置文件
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="500"
android:propertyName="pathData"
android:valueFrom="M582,490L582,530L882,530L882,490ZM582,640L582,680L882,680L882,640ZM582,790L582,830L882,830L882,790Z"
android:valueTo="M592,670L562,700L662,800L692,770ZM662,800L692,830L792,730L762,700ZM762,700L792,730L892,630L862,600Z"
android:valueType="pathType" />
控制動(dòng)畫(huà)運(yùn)行的是一個(gè)objectAnimator
尤莺,此處把objectAnimator
包裹在一個(gè)set
中也是可以的,說(shuō)白了就是執(zhí)行這個(gè)動(dòng)畫(huà)文件生棍。
duration
用來(lái)指定動(dòng)畫(huà)的持續(xù)時(shí)間颤霎。
propertyName
中的pathData指的就是矢量圖中的pathData。
valueFrom
和valueTo
一個(gè)是起始路徑足绅,一個(gè)是結(jié)束路徑捷绑,可以想到,這個(gè)動(dòng)畫(huà)就是在持續(xù)修改pathData氢妈,從而達(dá)到展示動(dòng)畫(huà)的效果。而valueFrom
和valueTo
的值是直接從先前準(zhǔn)備的矢量圖中復(fù)制過(guò)來(lái)的段多,所以那個(gè)結(jié)束狀態(tài)的矢量圖中唯一有用的東西就是pathData屬性首量,沒(méi)有那個(gè)文件也無(wú)所謂。
valueType
這里必須填寫(xiě)pathType进苍,這是專(zhuān)門(mén)用來(lái)計(jì)算path的類(lèi)型加缘。
- 動(dòng)畫(huà)創(chuàng)建好了之后就開(kāi)始創(chuàng)建動(dòng)畫(huà)矢量圖文件。
之前我們通過(guò)@drawable/icon_filter_off
的方式就可以引用矢量圖觉啊,此時(shí)的矢量圖是靜態(tài)的拣宏,因?yàn)檫@個(gè)矢量圖最外層由vector
包裹,現(xiàn)在需要一個(gè)動(dòng)態(tài)的矢量圖杠人,所以我們?cè)?code>res\drawable文件夾下創(chuàng)建animated_filter_on.xml
勋乾,代碼如下:
// animated_filter_on.xml 動(dòng)畫(huà)矢量圖文件
<?xml version="1.0" encoding="utf-8"?>
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/icon_filter_off">
<target
android:name="status"
android:animation="@animator/filter_turn_on" />
</animated-vector>
此時(shí),文件的最外層由animated-vector
包裹嗡善,同時(shí)需要添加一個(gè)drawable
參數(shù)辑莫,這個(gè)drawable
用于指定動(dòng)畫(huà)應(yīng)用于那個(gè)矢量圖上,我們是要從未啟用狀態(tài)變成啟用狀態(tài)罩引,所以是在未啟用狀態(tài)開(kāi)始執(zhí)行動(dòng)畫(huà)各吨,在動(dòng)畫(huà)未開(kāi)始的時(shí)候展示的也是未啟用狀態(tài)。此處我們指定為@drawable/icon_filter_off
袁铐。
內(nèi)部有一個(gè)target
標(biāo)簽揭蜒,這個(gè)標(biāo)簽可以有多個(gè)横浑,分別對(duì)應(yīng)不同的動(dòng)畫(huà),但同一個(gè)path
只能應(yīng)用一個(gè)動(dòng)畫(huà)屉更。
name
用于指定要執(zhí)行動(dòng)畫(huà)的path
伪嫁。status正是我們?yōu)橛蚁陆切D標(biāo)path設(shè)置的名稱(chēng)。
animation
用于指定需要執(zhí)行的動(dòng)畫(huà)偶垮。此處引用我們剛剛創(chuàng)建的動(dòng)畫(huà)資源@animator/filter_turn_on
张咳。
當(dāng)我們創(chuàng)建好動(dòng)畫(huà)矢量圖之后,頁(yè)面中引用的資源就不再是之前的靜態(tài)矢量圖了似舵,需要把ImageView
的圖片替換成@drawable/animated_filter_on
- 準(zhǔn)備工作已經(jīng)就緒脚猾,接下來(lái)就讓我們的矢量圖動(dòng)起來(lái)。
在點(diǎn)擊事件中將ImageView
的drawable
提取出來(lái)砚哗,將其轉(zhuǎn)換成android.graphics.drawable.AnimatedVectorDrawable
類(lèi)型龙助,然后調(diào)用start()
方法即可。
// java
AnimatedVectorDrawable drawable= (AnimatedVectorDrawable) imageViewFilter.getDrawable();
drawable.start();
// kotlin
(imageViewFilter.drawable as AnimatedVectorDrawable).start()
經(jīng)過(guò)這么多的步驟蛛芥,我們終于做出了一個(gè)矢量圖動(dòng)畫(huà)提鸟,而且是一個(gè)。說(shuō)實(shí)話(huà)仅淑,有點(diǎn)累称勋,然而我這個(gè)狀態(tài)切換的動(dòng)畫(huà)一套就要兩個(gè),所以我又加了一個(gè)回來(lái)的動(dòng)畫(huà)和對(duì)應(yīng)的動(dòng)畫(huà)矢量圖涯竟,一共六個(gè)文件赡鲜,完成了篩選狀態(tài)的兩個(gè)切換動(dòng)畫(huà)。這還是比較簡(jiǎn)單的實(shí)現(xiàn)方式庐船,對(duì)于兩種狀態(tài)切換的動(dòng)畫(huà)银酬,網(wǎng)上還有一種使用selector的方式,這種方式更麻煩筐钟,而且使用方法并沒(méi)有簡(jiǎn)單一些揩瞪,所以我的選擇是在需要切換狀態(tài)的時(shí)候更改ImageView
的圖片資源,然后再執(zhí)行動(dòng)畫(huà)篓冲。
// kotlin
// 這是點(diǎn)擊事件中切換狀態(tài)樣式的代碼李破,實(shí)際業(yè)務(wù)中可能會(huì)根據(jù)業(yè)務(wù)數(shù)據(jù)判斷是否需要切換。
imageViewFilter.run {
if (isSelected) {
setImageResource(R.drawable.animated_filter_off)
(drawable as AnimatedVectorDrawable).start()
}else{
setImageResource(R.drawable.animated_filter_on)
(drawable as AnimatedVectorDrawable).start()
}
isSelected = !isSelected
}
trimPath動(dòng)畫(huà)
trimPath動(dòng)畫(huà)相當(dāng)于是改變了矢量圖繪制的位置喷屋,是從頭開(kāi)始畫(huà)還是從80%的位置開(kāi)始畫(huà),然后再動(dòng)態(tài)的修改這個(gè)百分比密任,從而達(dá)到動(dòng)畫(huà)的效果涌萤。理解起來(lái)倒不是很難。
先放一個(gè)我使用trimPath動(dòng)畫(huà)做的loading效果,這個(gè)動(dòng)畫(huà)效果被我用在LoadingDialog中,在界面加載的時(shí)候會(huì)重復(fù)播放這個(gè)動(dòng)畫(huà)老玛。
為了做到這種效果镜廉,我們一共需要以下幾個(gè)步驟:
1. 設(shè)計(jì)矢量圖塔插,并將其添加到安卓項(xiàng)目中。
2. 根據(jù)動(dòng)畫(huà)需求,添加動(dòng)畫(huà)配置文件茸炒。
3. 配置動(dòng)畫(huà)矢量圖文件壁公,在使用的地方進(jìn)行引用感论。
4. 開(kāi)始執(zhí)行動(dòng)畫(huà)。
- 首先是設(shè)計(jì)一個(gè)自己的線(xiàn)狀動(dòng)畫(huà)贮尖,我的靈感來(lái)自于心電圖笛粘,一個(gè)人活著的話(huà)會(huì)有一個(gè)周期性的心電圖波動(dòng),而我用這個(gè)形狀來(lái)代表APP正在干活湿硝。在學(xué)習(xí)了矢量圖的繪制之后薪前,一個(gè)心電圖的形狀并不難,只是計(jì)算坐標(biāo)比較累关斜。
// icno_loading.xml loading的完全體樣式
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:width="200dp"
android:height="200dp"
android:tint="#000000"
android:viewportWidth="1024"
android:viewportHeight="1024">
<path
android:name="load"
android:pathData="M82,512h280l60,-172l60,430l80,-602l70,430l30,-86h280"
android:strokeWidth="20"
android:strokeColor="#000000"
android:trimPathStart="0"
android:trimPathEnd="0"
tools:trimPathEnd="1" />
</vector>
android:name="load"
不用多說(shuō)示括,這個(gè)是我們做動(dòng)畫(huà)時(shí)路徑名稱(chēng)。這里為了讓心電圖路徑更清晰痢畜,我設(shè)置了描邊寬度為20(android:strokeWidth="20"
)垛膝,同時(shí)還要設(shè)置描邊的顏色才能展示出來(lái)。后面的android:trimPathStart="0"
和android:trimPathEnd="0"
是本次trimPath動(dòng)畫(huà)的重點(diǎn)丁稀。
android:trimPathStart="0"
- 路徑繪制的起始點(diǎn)吼拥,范圍[0,1]。
android:trimPathEnd="0"
- 路徑繪制的終點(diǎn)线衫,范圍[0,1]凿可。實(shí)際展示的效果就是從起點(diǎn)畫(huà)到終點(diǎn)的路徑。當(dāng)繪制范圍超過(guò)[0,1]時(shí)也可以畫(huà)出來(lái)授账,類(lèi)似于循環(huán)繪制枯跑。具體效果就自行體會(huì)吧。
這兩個(gè)屬性都設(shè)置為0是因?yàn)閯?dòng)畫(huà)的起始幀都為0白热,然后通過(guò)objectAnimator
慢慢把這兩個(gè)屬性變?yōu)?敛助,這樣一個(gè)慢慢增長(zhǎng)的動(dòng)畫(huà)就形成了。
網(wǎng)絡(luò)上一個(gè)橫線(xiàn)變成搜索按鈕的示例是將這兩個(gè)屬性分別應(yīng)用到了兩個(gè)path
上屋确,而我是將兩個(gè)屬性同時(shí)應(yīng)用到一個(gè)path
上纳击,原理都是一樣的续扔。
- 接下來(lái)為剛剛預(yù)留的屬性配置動(dòng)畫(huà)效果,要做到和心電圖差不多的掃描效果评疗,要同時(shí)修改路徑的起始點(diǎn)和終點(diǎn)测砂,這樣可以只展示整個(gè)路徑中的某一段。而且兩個(gè)動(dòng)畫(huà)要有一定間隔百匆,如果同步執(zhí)行砌些,起點(diǎn)和終點(diǎn)肯定是一致的,這樣什么都畫(huà)不出來(lái)加匈。
// loading.xml loading動(dòng)畫(huà)配置
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
android:duration="3000"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:propertyName="trimPathStart"
android:repeatCount="infinite"
android:startOffset="1000"
android:valueFrom="0"
android:valueTo="1"
android:valueType="floatType" />
<objectAnimator
android:duration="3000"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:propertyName="trimPathEnd"
android:repeatCount="infinite"
android:valueFrom="0"
android:valueTo="1"
android:valueType="floatType" />
</set>
在配置文件中存璃,我將兩個(gè)動(dòng)畫(huà)都設(shè)置為3秒且循環(huán)播放,起始點(diǎn)的動(dòng)畫(huà)慢于終點(diǎn)的動(dòng)畫(huà)1秒雕拼,達(dá)到只畫(huà)中間1秒間隔線(xiàn)段的效果纵东。和路徑變形動(dòng)畫(huà)的區(qū)別是android:valueType="floatType"
,我們只需要計(jì)算從0到1的數(shù)字啥寇,然后應(yīng)用到trimPathStart
和trimPathEnd
字段上偎球。至此,loading的動(dòng)畫(huà)就配置完了辑甜。
- 所需的資源都準(zhǔn)備好了之后就創(chuàng)建一個(gè)動(dòng)畫(huà)矢量圖文件衰絮,在這個(gè)文件中將靜態(tài)的矢量圖和動(dòng)畫(huà)配置綁定到一起。
// animated_loading.xml 用于界面的動(dòng)畫(huà)矢量圖文件
<?xml version="1.0" encoding="utf-8"?>
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/icon_loading">
<target
android:name="load"
android:animation="@animator/loading" />
</animated-vector>
這一步已經(jīng)沒(méi)什么可說(shuō)的了磷醋,就是將指定的矢量圖中指定的路徑設(shè)置一個(gè)指定的動(dòng)畫(huà)猫牡。
- 最后料滥,將animated_loading設(shè)置到目標(biāo)
ImageView
中性穿,在合適的時(shí)機(jī)開(kāi)始動(dòng)畫(huà)矾利。啟動(dòng)動(dòng)畫(huà)的方式和路徑變換一致靶衍,然后就可以欣賞自己制作的動(dòng)畫(huà)效果了。
結(jié)語(yǔ)
通過(guò)幾天的學(xué)習(xí)漩绵,已經(jīng)大致掌握了矢量圖的展示及動(dòng)畫(huà)的制作鼻由,但這一套流程下來(lái)成本比較高寇仓,是程序員方式的動(dòng)畫(huà)制作流程你雌。除了制作成本归薛,創(chuàng)意成本也是相當(dāng)高的,一個(gè)好的創(chuàng)意能極大的提升用戶(hù)體驗(yàn)匪蝙,而好多時(shí)候我們的創(chuàng)意能夠被實(shí)現(xiàn)也是很困難的。希望以后能實(shí)現(xiàn)一些更好的效果习贫,讓用戶(hù)使用起來(lái)更舒服逛球。
參考文章
SVG—最簡(jiǎn)單的SVG動(dòng)畫(huà)
SVG路徑(path)中的圓弧(A)指令的語(yǔ)法說(shuō)明及計(jì)算邏輯
Android中的矢量圖
Android高級(jí)動(dòng)畫(huà)(2)