android矢量動畫的使用 & Path.java與pathData

背景

  • 位圖:像素表示圖像
  • 矢量圖:數學方程表示圖像 維基百科
  • 矢量動畫:不斷改變矢量圖的屬性(方程式)形成動畫
  • 屬性動畫(ValueAnimator):在指定的時間內(Time),指定的變化速率下(TimeInterpolator),不斷返回指定的(TypeEvaluator)中間值的"中間值生成器"

實現

  • Step1
創建'實現矢量動畫需要的三個文件':矢量圖、屬性動畫、助手類  
res/drawable/vector.xml  
res/animator/object_animator.xml  
res/drawable/animated_vector_drawable.xml  
  • Step2
    <ImageView
    android:src="@drawable/animated_vector_drawable"
    …/>
  • Step3
開始動畫  
    mImageView.getDrawable().start();
 注1:助手類指 AnimatedVectorDrawable.java
     This class uses ObjectAnimator and AnimatorSet to animate the
  properties of a VectorDrawable to create an animated drawable.
 注2:Step1中的三個文件
     <!--矢量圖 res/drawable/vector.xml -->
     <vector xmlns:android="http://schemas.android.com/apk/res/android"
             android:width="64dp"
             android:height="64dp"
             android:viewportWidth="64"
             android:viewportHeight="64">
         <group
             android:name="group_demo"
             android:pivotX="32"
             android:pivotY="32"
             >
             <path
                 android:name="path_demo"
                 android:pathData="M0,0 L32,32 L32,0 z"
                 android:strokeWidth="2"
                 android:strokeColor="#000000"/>
         </group>
     </vector>

     <!--屬性動畫 res/animator/object_animator.xml -->
     <objectAnimator
            xmlns:android="http://schemas.android.com/apk/res/android"
            android:duration="1000"
            android:propertyName="rotation"
            android:valueFrom="0"
            android:valueTo="360"/>

     <!--助手類 res/drawable/animated_vector_drawable.xml -->
     <animated-vector
             xmlns:android="http://schemas.android.com/apk/res/android"
             //指定矢量圖
             android:drawable="@drawable/vector">
             <target
                 //指定將要進行動畫的group或path,該名稱在vector.xml中定義
                 android:name="group_demo"
                 //指定動畫類型
                 android:animation="@animator/object_animator"/>
     </animated-vector>
 注3:三個文件可合併寫到一個文件,方式如下
     https://developer.android.google.cn/guide/topics/graphics/vector-drawable-resources

補充一:SVG與VectorDrawable

  • SVG
    可伸縮矢量圖形(Scalable Vector Graphics),矢量圖的一種表述形式,  
遵從XML語法,用文本格式的描述性語言來描述圖像內容,文件後綴爲".svg"
例如:
     test.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" />
         </svg>
  • VectorDrawable
    安卓中使用矢量圖,需將"xxx.svg"轉換爲上文中提到的res/drawable/vector.xml
的格式(即最終的VectorDrawable.java)
    SVG圖片需要UI提供,也可以手動編寫一些簡單的vector.xml

補充二:VectorDrawable支持的元素、屬性

  • VectorDrawable並沒有支持所有的SVG規範,目前支持的元素、屬性如下
        <vector>
            android:name
            //矢量圖默認寬高
            android:width
            android:height
            //畫布寬高
            android:viewportWidth
            android:viewportHeight
            android:tint
            android:tintMode
            android:autoMirrored
            android:alpha
        <group>
            android:name
            android:rotation
            //旋轉、縮放一組path時的中心點,相對於畫布寬高
            android:pivotX
            android:pivotY
            android:scaleX
            android:scaleY
            android:translateX
            android:translateY
        <path>
            android:name
            android:pathData
            android:fillColor
            android:strokeColor
            android:strokeWidth
            android:strokeAlpha
            android:fillAlpha
            android:trimPathStart
            android:trimPathEnd
            android:trimPathOffset
            android:strokeLineCap
            android:strokeLineJoin
            android:strokeMiterLimit
            android:fillType
        <clip-path>
            android:name
            android:pathData
   注1:放大縮小不失真是矢量圖特性,矢量圖需要有固有寬高的原因:
   android/frameworks/base/libs/hwui/VectorDrawable.h中提到  
   "VectorDrawables are drawn into bitmap caches first"

   注2:其餘元素、屬性的說明可查看
   https://developer.android.google.cn/reference/android/graphics/drawable/VectorDrawable  
   https://www.w3.org/TR/SVG11

補充三:path元素及pathData屬性

  • 若把"元素path"看成Android中Path.java的對象(解析vector.xml構建對象時)
  • 那麼"屬性pathData"中的數據就代表了Path.java中相應的方法(構建對象時依據這些數據調用相應的方法)
例如:
      自定義View時,可以通過如下操作畫出一個三角形
      public class XXX extends View {
          @Override
          protected void onDraw(Canvas canvas) {
              Path path = new Path();
              path.moveTo(0, 0);
              path.lineTo(32, 32);
              path.lineTo(32, 0);
              path.close();
              canvas.drawPath(path, getPaint());
          }
      }

      vector.xml中pathData配置如下亦代表三角形
      <vector >
          <path
              android:name="path_demo"
              android:pathData="M0,0 L32,32 L32,0 z"
            />
      </vector>

      pathData中數據“對應”Path.java中相應的方法
          M對應moveTo()
          L對應lineTo()
          z對應close()
   注1:pathData中M,L,Z...等的語法含義
         M:move to 落筆位置
         L:line to 劃線
         Z:close 閉合
         A:elliptical arc 圓弧
    詳情可參閱 https://www.w3.org/TR/SVG11/paths.html
   注2:附件VectorDemo有該例

補充四:path元素與Path.java

  • 補充三中不嚴謹的地方
    解析vector.xml時,<path>生成的是VFullPath對象而非Path.java的實例.但二者
  最終歸宿都是/android/external/skia/src/core/SkPath.cpp
    從這點看,補充三中的類比雖不嚴謹,但不是很過分
  • "歸宿都是SkPath"的依據
vector.xml中Path元素及pathData屬性
    inflate()時
        android/frameworks/base/graphics/java/android/graphics/drawable/VectorDrawable.java
        nSetPathString(...)
        android/frameworks/base/core/jni/android_graphics_drawable_VectorDrawable.cpp
        setPathString(...)
        /android/frameworks/base/libs/hwui/VectorDrawable.h
        void setData(const Data& data)

    draw()時
        android/frameworks/base/graphics/java/android/graphics/drawable/VectorDrawable.java
        nDraw(...)
        android/frameworks/base/core/jni/android_graphics_drawable_VectorDrawable.cpp
        draw(...)
        android/frameworks/base/libs/hwui/VectorDrawable.cpp
        Tree::draw(...)
        Tree::drawStaging(...)
        Tree::updateBitmapCache(...)
        Group::draw(...)
        Path::draw(...)
        const SkPath& Path::getUpdatedPath() {
          VectorDrawableUtils::verbsToPath(&mSkPath, mProperties.getData());
          return mSkPath;
        }
Path.java及canvas.drawPath()
    構造Path時
        android/frameworks/base/graphics/java/android/graphics/Path.java
        public Path() {
              mNativePath = init1();
           }
        android/frameworks/base/core/jni/android/graphics/Path.cpp
        static jlong init1(JNIEnv* env, jobject clazz) {
            return reinterpret_cast<jlong>(new SkPath());
           }

    canvas.drawPath()時
        android/frameworks/base/graphics/java/android/graphics/Canvas.java
        public void drawPath(Path,Paint)
        android/frameworks/base/core/jni/android_graphics_Canvas.cpp
        static void drawPath(...) {
            const SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
            const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
            get_canvas(canvasHandle)->drawPath(*path, *paint);
        }

補充五:參考及Demo

  • 參考
  1.https://zh.wikipedia.org/wiki/%E7%9F%A2%E9%87%8F%E5%9B%BE%E5%BD%A2
  2.https://zh.wikipedia.org/wiki/%E5%8F%AF%E7%B8%AE%E6%94%BE%E5%90%91%E9%87%8F%E5%9C%96%E5%BD%A2
  3.https://www.w3.org/TR/SVG11/paths.html
  4.https://developer.android.google.cn/reference/android/graphics/drawable/VectorDrawable
  5.https://developer.android.google.cn/guide/topics/graphics/drawable-animation
  6.https://developer.android.google.cn/reference/android/graphics/drawable/AnimatedVectorDrawable#OneXML
  7.https://developer.android.google.cn/studio/write/vector-asset-studio
  8.https://www.androiddesignpatterns.com/2018/11/android-studio-svg-to-vector-cli.html
  9.屬性動畫機制不只是針對view來設計的allows you to animate almost anything,regardless of whether it draws to the screen or not.
    https://developer.android.google.cn/guide/topics/graphics/prop-animation
  10.文中開頭提到的屬性動畫定義、矢量動畫定義源自fyang,維基中沒找到相關正式定義,百度中對矢量動畫的定義有些"生硬"
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章