Android SVG動畫

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()");
    }
}
發佈了98 篇原創文章 · 獲贊 12 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章