Android 5.X SVG矢量動畫機制
概要
Google在Android 5.X中增加了對SVG矢量圖形的支持,首先大概瞭解一下SVG。
- 可伸縮的矢量圖形(Scalable Vector Graphics)
- 使用XML格式定義圖形
- 圖像放大或改變尺寸的情況下其圖形質量不會有損失
- 萬維網聯盟標準
總的來說SVG是一個繪圖標準。與Bitmap對比,SVG最大的優點就是放大不會失真。
< path >標籤
使用path標籤創建svg,就像使用指令的方式來控件一隻畫筆。
常用的指令有:
- M = moveto 移動繪製點
- L = lineto 直線
- H = horizontal lineto 水平線
- V = vertical lineto 豎直線
- C = curveto 三次貝塞爾曲線
- S = smooth curveto 三次貝塞爾曲線
- Q = quadratic Belzier curve 二次貝塞爾曲線
- T = smooth quadratic Belzier curveto 映射前面路徑後的終點
- A = elliptical Arc 圓弧
Z = closepath 閉合
註釋:以上所有命令均允許小寫字母。大寫表示絕對定位,小寫表示相對定位。
Android中使用SVG
Coogle在Android5.x中提供了下面兩個新的Api來幫助支持SVG。
- VectorDrawable
- AnimatedVectorDrawable
VectorDrawable
其中,VectorDrawable讓你可一個創建基於XML的SVG的圖形,並結合AnimatedVectorDrawable來實現動畫效果。例如要實現下圖效果。
簡單分析:一條下滑線和一個搜索的logo,我就可以用代碼這樣定義:
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="320dp"
android:height="45dp"
android:viewportWidth="320"
android:viewportHeight="45">
<path
android:name="search"
android:strokeLineCap="round"
android:strokeColor="#f8fc03"
android:strokeWidth="2"
android:pathData="
M 290,30
A 15,15,0,1,1,291,29
L 300,42"></path>
<path
android:name="bar"
android:strokeLineCap="round"
android:strokeColor="#f8fc03"
android:strokeWidth="2"
android:pathData="
M 10,42
L 300,42"></path>
</vector>
代碼中標籤有兩個重要標籤path,vector。
vector:用於定義整個畫布。
width:畫布的寬度。
height:畫布的高度。
viewportWidth:將具體的寬度劃分成相對的單位單元。320dp分成320個單元。
viewportHeight:將具體的高度劃分成相對的單元單位。45dp被分成48個單元。
(ps,高寬保持相對比例,否則會發生圖片扭曲)
path:用於畫出具體的圖案,類似於畫筆。
name:聲明一個標記。類似於id。 便於對其做動畫的時候可以找到該節點。
pathData:矢量圖SVG 的描述
strokeWidth:畫筆的寬度
strokeColor:畫筆的顏色
strokeAlpha:透明度
strokeLineCap:畫出線條的結束點的形狀。正方向或圓角矩形。。。
AnimatedVectorDrawable
圖形生成後,添加如下動畫
動畫分析
- 當點擊輸入框時,搜索logo消失,下滑線從右到左生成。
- 當點擊非輸入框時,下劃線從左到右消失,搜索logo生成。
動畫一的實現:
drawable/draw_animator1.xml
<?xml version="1.0" encoding="utf-8"?>
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/vec_search">
<target
android:animation="@animator/search_anim_empty"
android:name="search"></target>
<target
android:animation="@animator/bar_anim_fill"
android:name="bar"></target>
</animated-vector>
通過上面代碼可知,AnimatedVectorDrawable相當於一個膠水的作用,將
VectorDrawable與Animator連接起來。
< animated-vector>
drawable:目標SVG.
< targer>:對於SVG中的每一個< path >定義不同的動畫。
name: 目標文件的標識。
animation:動畫。
< /targer>
< /animated-vector>
animator/search_anim_empty.xml
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:valueType="floatType"
android:propertyName="trimPathStart"
android:valueFrom="0"
android:valueTo="1"
android:duration="1000"
android:interpolator="@android:interpolator/linear_out_slow_in"></objectAnimator>
動畫屬性trimPathEnd這個字段之前未出現過。它也是的一個屬性,其決定的是節點所畫出線條顯示的百分比。 0~1 代表 從開始到結束顯示的百分比。
同時也有一個trimPathStart,這個字段顯示的也是百分比。不過其表示的是不顯示的百分比。0~1代表從開始隱藏的百分比。
ps: 動畫定義的都是屬性動畫,所以需要放在animator文件夾中
ps: 如果要改變path本身,propertyName=”pathData”valueType=”pathType”
animator/bar_anim_fill.xml
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:valueType="floatType"
android:propertyName="trimPathStart"
android:valueFrom="1"
android:valueTo="0"
android:duration="1000"
android:interpolator="@android:interpolator/linear_out_slow_in"></objectAnimator>
動畫二實現:
drawable/draw_animator2.xml
<?xml version="1.0" encoding="utf-8"?>
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/vec_search">
<target
android:animation="@animator/search_anim_fill"
android:name="search"></target>
<target
android:animation="@animator/bar_anim_empty"
android:name="bar"></target>
</animated-vector>
animator/search_anim_fill.xml
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:valueType="floatType"
android:propertyName="trimPathStart"
android:valueFrom="1"
android:valueTo="0"
android:duration="1000"
android:interpolator="@android:interpolator/linear_out_slow_in"></objectAnimator>
animator/bar_anim_empty.xml
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:valueType="floatType"
android:propertyName="trimPathStart"
android:valueFrom="0"
android:valueTo="1"
android:duration="1000"
android:interpolator="@android:interpolator/linear_out_slow_in"></objectAnimator>
佈局文件:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:onClick="lost_foucs">
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true">
<ImageView
android:id="@+id/img_svg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/vec_anim_search"/>
<EditText
android:id="@+id/et"
android:layout_width="250dp"
android:layout_height="45dp"
android:background="@android:color/transparent"/>
</FrameLayout>
</RelativeLayout>
java代碼:
public class SVGActivity extends Activity{
ImageView img;
private EditText editText;
private AnimatedVectorDrawable animate1;
private AnimatedVectorDrawable animate2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout_svg);
img = (ImageView) findViewById(R.id.img_svg);
editText = (EditText) findViewById(R.id.et);
animate1 = (AnimatedVectorDrawable) getResources().getDrawable(R.drawable.draw_animator1);
animate2 = (AnimatedVectorDrawable) getResources().getDrawable(R.drawable.draw_animator2);
editText.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
img.setImageDrawable(animate1);
animate1.start();
}
});
}
public void lost_foucs(View view){
img.setImageDrawable(animate2);
animate2.start();
}
@Override
protected void onResume() {
super.onResume();
Log.i("wangGV", "onResume()");
// throw new NullPointerException();
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.i("wangGV", "onDestroy()");
}
}