美文网首页Android开发Android开发经验谈Android技术知识
svg Vector 章节(2):绘制图形并改变groups p

svg Vector 章节(2):绘制图形并改变groups p

作者: zhongjh | 来源:发表于2019-12-26 02:00 被阅读0次

    1. 绘制并改变groups paths

    在上一节中,我们学习了如何path通过直接修改其属性(如不透明度和颜色)来更改的外观。除此之外,VectorDrawables还支持使用标记进行组转换<group>,这允许我们path使用以下可设置动画的属性一次将转换应用于多个:

    名称 元素类型 值类型 解释
    android:pivotX <group> float 定义缩放和旋转等动作时候,会以该 group 的 pivotX的值作为参考点。该值相对于 vector 的 viewport 值来指定的。
    android:pivotY <group> float 定义缩放和旋转等动作时候,会以该 group 的 pivotY的值作为参考点。该值相对于 vector 的 viewport 值来指定的。
    android:rotation <group> float 定义该 group 的路径旋转多少度,这样图片就被旋转了
    android:scaleX <group> float 定义 X 轴的缩放倍数
    android:scaleY <group> float 定义 Y 轴的缩放倍数
    android:translateX <group> float 定义移动 X 轴的位移。相对于 vector 的 viewport 值来指定的。
    android:translateY <group> float 定义移动 Y 轴的位移。相对于 vector 的 viewport 值来指定的。

    了解嵌套group转换的应用顺序很重要。要记住的两个规则是:

    1. 子group继承其父组所应用的转换,意思是当前每次的转变都是以上一个为准
    2. group按比例,旋转和平移的顺序对其进行的转换。



    那么让我们通过一些简单的例子来学习,以下是group应用于集中图标的转换相关例子:

    1.1 放大转换相关例子:

    放大转换.png
    <vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="48dp"
        android:height="48dp"
        android:viewportHeight="12"
        android:viewportWidth="12">
    
        <!-- 1.以pivotX和pivotY都是坐标为6点作为中心,以scaleX也即是横向放大1.5倍 -->
        <group
            android:pivotX="6"
            android:pivotY="6"
            android:scaleX="1.5">
            <path
                android:name="iconPath"
                android:fillColor="@android:color/white"
                android:pathData="M 4,2.5 L 4,9.5 L 9.5,6 Z" />
        </group>
    
    </vector>
    

    1.2 旋转90度相关例子:

    旋转90度
    <vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="48dp"
        android:height="48dp"
        android:viewportWidth="12"
        android:viewportHeight="12">
    
        <!-- 2.以pivotX和pivotY都是坐标为6点作为中心,而rotation顺时针旋转90度 -->
        <group
            android:pivotX="6"
            android:pivotY="6"
            android:rotation="90">
            <path
                android:name="iconPath"
                android:fillColor="@android:color/white"
                android:pathData="M 4,2.5 L 4,9.5 L 9.5,6 Z" />
        </group>
    
    </vector>
    

    1.3 横向移动2格相关例子:

    横向移动2格
    <vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="48dp"
        android:height="48dp"
        android:viewportWidth="12"
        android:viewportHeight="12">
    
        <!-- 3.这个是平移X角度即使横向移动2格 -->
        <group android:translateX="2" >
            <path
                android:name="iconPath"
                android:fillColor="@android:color/white"
                android:pathData="M 4,2.5 L 4,9.5 L 9.5,6 Z" />
        </group>
    
    </vector>
    

    1.4 3个group结合后的动作相关例子:

    3个group结合后的动作
    请记住,group是根据顺序而变化,您可以尝试不同的顺序会发现最终显示的结果不一样
    <vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="48dp"
        android:height="48dp"
        android:viewportWidth="12"
        android:viewportHeight="12">
    
        <!-- 1.以pivotX和pivotY都是坐标为6点作为中心,而scaleX也即是横向放大1.5倍 -->
        <group android:scaleX="1.5" android:pivotX="6" android:pivotY="6">
            <!-- 2.以pivotX和pivotY都是坐标为6点作为中心,而rotation顺时针旋转90度 -->
            <group android:rotation="90" android:pivotX="6" android:pivotY="6">
                <!-- 3.这个是平移X角度即使横向移动2格 -->
                <group android:translateX="2">
                    <path
                        android:name="iconPath"
                        android:fillColor="@android:color/white"
                        android:pathData="M 4,2.5 L 4,9.5 L 9.5,6 Z" />
                </group>
            </group>
        </group>
    
    </vector>
    

    将 <group> 组合一起可以实现各种炫酷效果。

    在上面每个图中,每个图标的源代码都可以在demo2地址上找到

    2.实现简单的动画

    在讲解动画之前,我们先了解动画是基于xml设置,而xml的标签意思设置如下:

    <set android:ordering=["together" | "sequentially"]>
    
        <objectAnimator
            android:propertyName="string"
            android:duration="int"
            android:valueFrom="float | int | color"
            android:valueTo="float | int | color"
            android:startOffset="int"
            android:repeatCount="int"
            android:repeatMode=["repeat" | "reverse"]
            android:valueType=["intType" | "floatType"] />
    
        <animator
            android:duration="int"
            android:valueFrom="float | int | color"
            android:valueTo="float | int | color"
            android:startOffset="int"
            android:repeatCount="int"
            android:repeatMode=["repeat" | "reverse"]
            android:valueType=["intType" | "floatType"] />
    
        <set>
            ...
        </set>
    </set>
    
    
    名称 值类型 详细解释
    <set> 它是一个集合,包含了其他的元素,包括, 和其他的元素,它代表的就是一个AnimatorSet对象
    android:ordering "together" / "sequentially" 指定集合中动画播放的顺序。它具有两种类型的值:sequentially和together。第一个表示顺序执行,第二个表示同时执行。默认是together。
    <objectAnimator> 它指定一个对象的属性动画,表示一个ObjectAnimator对象。
    android:propertyName string 属性名称,例如一个view对象的”alpha”和”backgroundColor”。
    android:valueFrom float/int /color 变化开始值
    android:valueTo float 变化结束值
    android:valueType "intType"/"floatType" 变化值类型,它有两种值:intType和floatType,第二种为默认值
    android:duration "int" 持续时间
    android:startOffset "int" 动画开始延迟时间
    android:repeatCount "int" 重复次数,-1表示无限重复
    android:repeatMode "repeat" / "reverse" 重复模式,前提是android:repeatCount为-1,它有两种值:”reverse”和”repeat”,第一个表示反向重复,第二个为顺序重复。
    <animator> 它对应的就是ValueAnimator对象。拥有的属性跟<objectAnimator>一样

    下面将学习三个不同动画的例子让我们更加深入了解!

    2.1 展开折叠效果

    展开折叠效果.gif

    展开/折叠图标是使用两个矩形路径绘制。单击时,两个路径同时旋转90°并垂直平移以创建过渡。

    首先,让我们看看形成这个绘制和动画的代码:

    <?xml version="1.0" encoding="utf-8"?>
    <animated-selector xmlns:android="http://schemas.android.com/apk/res/android">
    
        <!-- 展开的图片 -->
        <item
            android:id="@+id/expanded"
            android:drawable="@drawable/ic_expanded"
            android:state_checked="true"/>
    
        <!-- 收缩的图片 -->
        <item
            android:id="@+id/collapsed"
            android:drawable="@drawable/ic_collapsed" />
    
        <!-- 从收缩过渡到展开的动画 -->
        <transition
            android:drawable="@drawable/avd_collapsed_to_expanded"
            android:fromId="@id/collapsed"
            android:toId="@id/expanded" />
    
        <!-- 从展开过渡到收缩的动画 -->
        <transition
            android:drawable="@drawable/avd_expanded_to_collapsed"
            android:fromId="@id/expanded"
            android:toId="@id/collapsed" />
    
    </animated-selector>
    

    接下来让我们一步一步解析这4块注释,首先是看看展开图片怎么组成的,上面说到,这个图形是由两个矩形绘制而成的

    2.1.1 首先让我们看看展开的图片

    <vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="24dp"
        android:height="24dp"
        android:tint="?attr/colorControlNormal"
        android:viewportWidth="24"
        android:viewportHeight="24">
    
        <!-- 整个画布移动到X12即是X中心点,而Y移动到9 -->
        <group
            android:name="chevron"
            android:translateX="12"
            android:translateY="9">
            <!-- 左边的矩形,向右正旋转45度,而Y移动+3=12,即是中心 -->
            <group
                android:name="leftBar"
                android:rotation="45">
                <group android:translateY="3">
                    <path
                        android:fillColor="@android:color/white"
                        android:pathData="M 1,-4 L 1,4 L -1,4 L -1,-4 Z" />
                </group>
            </group>
            <!-- 右边的矩形,向右正旋转135度,这个135度会导致矩形往Y轴下面延伸,所以后面一个group需要Y移动-3=6 -->
            <group
                android:name="rightBar"
                android:rotation="135">
                <group android:translateY="-3">
                    <path
                        android:fillColor="@android:color/white"
                        android:pathData="M 1,-4 L 1,4 L -1,4 L -1,-4 Z" />
                </group>
            </group>
        </group>
    
    </vector>
    

    https://shapeshifter.design/可以模仿出上图效果,基本结构:

    image.png

    2.1.2 然后是收缩的图片

    <vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="24dp"
        android:height="24dp"
        android:tint="?attr/colorControlNormal"
        android:viewportWidth="24"
        android:viewportHeight="24">
    
        <!-- 整个画布移动到X12即是X中心点,而Y移动到15偏下 -->
        <group
            android:name="chevron"
            android:translateX="12"
            android:translateY="15">
            <!-- 左边的矩形,向右正旋转135度后会比较偏上,而旋转后,《Y轴方向偏向左上角》,所以Y移动+3=18会往左上角继续偏移(即是往上),这样就比较居中了 -->
            <group
                android:name="leftBar"
                android:rotation="135">
                <group android:translateY="3">
                    <path
                        android:fillColor="@android:color/white"
                        android:pathData="M 1,-4 L 1,4 L -1,4 L -1,-4 Z" />
                </group>
            </group>
            <!-- 右边的矩形,向右正旋转45度,Y移动-3 -->
            <group
                android:name="rightBar"
                android:rotation="45">
                <group android:translateY="-3">
                    <path
                        android:fillColor="@android:color/white"
                        android:pathData="M 1,-4 L 1,4 L -1,4 L -1,-4 Z"/>
                </group>
            </group>
        </group>
    
    </vector>
    

    2.1.3 从收缩过渡到展开的动画

    <animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:aapt="http://schemas.android.com/aapt"
        android:drawable="@drawable/ic_collapsed">
    
        <!-- 这是整个画布的移动动画,收缩过渡到展开,偏下移到偏上,可以发现translateY的valueFrom和valueTo值都是对应收缩和展开图的相应位置的 -->
        <target android:name="chevron">
            <aapt:attr name="android:animation">
                <objectAnimator
                    android:duration="250"
                    android:interpolator="@android:interpolator/fast_out_slow_in"
                    android:propertyName="translateY"
                    android:valueFrom="15"
                    android:valueTo="9" />
            </aapt:attr>
        </target>
    
        <!-- 左边矩形旋转,用到了自定义动画差值器,同样的,旋转角度的值都是对应收缩和展开图的相应值的 -->
        <target android:name="leftBar">
            <aapt:attr name="android:animation">
                <objectAnimator
                    android:duration="200"
                    android:interpolator="@anim/pathmorph_expandcollapse"
                    android:propertyName="rotation"
                    android:valueFrom="135"
                    android:valueTo="45"
                    android:valueType="floatType" />
            </aapt:attr>
        </target>
    
        <!-- 左边矩形旋转,用到了自定义动画差值器,同样的,旋转角度的值都是对应收缩和展开图的相应值的 -->
        <target android:name="rightBar">
            <aapt:attr name="android:animation">
                <objectAnimator
                    android:duration="200"
                    android:interpolator="@anim/pathmorph_expandcollapse"
                    android:propertyName="rotation"
                    android:valueFrom="45"
                    android:valueTo="135"
                    android:valueType="floatType" />
            </aapt:attr>
        </target>
    
    </animated-vector>
    

    从展开过渡到收缩的动画差不多如此。

    2.2 闹钟“振铃”效果

    闹钟“振铃”效果.gif

    在闹钟图标绘制使用两个矩形路径其钟声。单击后,两个矩形路径围绕中心前后旋转,以产生“振铃”效果。

    首先我们看看闹钟这个图片如何“画”出来。
    老样子,打开https://material.io/resources/icons/?search=access_alarm&icon=access_alarm&style=baseline下载闹钟svg路径,根据上面动画效果显示,是上面两个矩形左右摆动,那我们分割出这两个矩形出来,到时候动画只针对这两个矩形做相应的动作即可。这里有个小诀窍就是以M(根据文章第一章M意思是移动到某点)为起点,Z为结点(根据文章第一章Z意思是闭合该画笔),所以最终闹钟的代码如下:

    <vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="24dp"
        android:height="24dp"
        android:tint="?attr/colorControlNormal"
        android:viewportWidth="24"
        android:viewportHeight="24">
    
        <!-- 顶部需要动画的两个矩形,可以看到button和button_pivot两个group分别translate加12,又translate减12,这样做目的是为了让后面的动画可以让这两个矩形围绕这12中心点抖动。
                至于具体原理我还查不到相关资料,如果有人知道麻烦留言,非常感谢!
                我猜测+12是扩大画布,-12又回到原位置,这样可以定点中心点在12利用抖动。-->
        <group
            android:name="button"
            android:translateX="12"
            android:translateY="12">
            <group
                android:name="button_pivot"
                android:translateX="-12"
                android:translateY="-12">
                <!-- 左边的矩形 -->
                <group
                    android:name="right_button">
                    <path
                        android:name="path_1"
                        android:fillAlpha="1"
                        android:fillColor="@android:color/white"
                        android:pathData="M 22 5.72 L 17.4 1.86 L 16.11 3.39 L 20.71 7.25 L 22 5.72 Z" />
                </group>
                <!-- 右边的矩形 -->
                <group
                    android:name="left_button">
                    <path
                        android:name="left_button_path"
                        android:fillAlpha="1"
                        android:fillColor="@android:color/white"
                        android:pathData="M 7.88 3.39 L 6.6 1.86 L 2 5.71 L 3.29 7.24 L 7.88 3.39 Z" />
                </group>
            </group>
        </group>
    
        <!-- 圆形和表针的组成 -->
        <group
            android:name="alarm"
            android:translateX="12"
            android:translateY="12">
            <group
                android:name="alarm_pivot"
                android:translateX="-12"
                android:translateY="-12">
                <!-- 表针 -->
                <group
                    android:name="alarm_hands">
                    <path
                        android:name="alarm_hands_path"
                        android:fillAlpha="1"
                        android:fillColor="@android:color/white"
                        android:pathData="M 12.5 8 L 11 8 L 11 14 L 15.75 16.85 L 16.5 15.62 L 12.5 13.25 L 12.5 8 Z" />
                </group>
                <!-- 圆形 -->
                <group
                    android:name="alarm_body">
                    <path
                        android:name="alarm_outline_path"
                        android:fillAlpha="1"
                        android:fillColor="@android:color/white"
                        android:pathData="M 12 4 C 7.03 4 3 8.03 3 13 C 3 17.97 7.02 22 12 22 C 16.97 22 21 17.97 21 13 C 21 8.03 16.97 4 12 4 Z M 12 20 C 8.13 20 5 16.87 5 13 C 5 9.13 8.13 6 12 6 C 15.87 6 19 9.13 19 13 C 19 16.87 15.87 20 12 20 Z" />
                </group>
            </group>
        </group>
    
    </vector>
    

    然后是非常简单的抖动动画

    <animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:aapt="http://schemas.android.com/aapt"
        android:drawable="@drawable/vd_clock_alarm">
    
        <!-- 只针对button进行抖动的动画,从0-8一直来回抖动,最终回到0 -->
        <target android:name="button">
            <aapt:attr name="android:animation">
                <set android:ordering="sequentially">
                    <objectAnimator
                        android:duration="33"
                        android:interpolator="@android:interpolator/fast_out_slow_in"
                        android:propertyName="rotation"
                        android:valueFrom="0"
                        android:valueTo="8" />
                    <objectAnimator
                        android:duration="67"
                        android:interpolator="@android:interpolator/fast_out_slow_in"
                        android:propertyName="rotation"
                        android:valueFrom="8"
                        android:valueTo="-8" />
                    <objectAnimator
                        android:duration="67"
                        android:interpolator="@android:interpolator/fast_out_slow_in"
                        android:propertyName="rotation"
                        android:valueFrom="-8"
                        android:valueTo="8" />
                    <objectAnimator
                        android:duration="67"
                        android:interpolator="@android:interpolator/fast_out_slow_in"
                        android:propertyName="rotation"
                        android:valueFrom="8"
                        android:valueTo="-8" />
                    <objectAnimator
                        android:duration="67"
                        android:interpolator="@android:interpolator/fast_out_slow_in"
                        android:propertyName="rotation"
                        android:valueFrom="-8"
                        android:valueTo="8" />
                    <objectAnimator
                        android:duration="67"
                        android:interpolator="@android:interpolator/fast_out_slow_in"
                        android:propertyName="rotation"
                        android:valueFrom="8"
                        android:valueTo="-8" />
                    <objectAnimator
                        android:duration="67"
                        android:interpolator="@android:interpolator/fast_out_slow_in"
                        android:propertyName="rotation"
                        android:valueFrom="-8"
                        android:valueTo="8" />
                    <objectAnimator
                        android:duration="67"
                        android:interpolator="@android:interpolator/fast_out_slow_in"
                        android:propertyName="rotation"
                        android:valueFrom="8"
                        android:valueTo="-8" />
                    <objectAnimator
                        android:duration="33"
                        android:interpolator="@android:interpolator/fast_out_slow_in"
                        android:propertyName="rotation"
                        android:valueFrom="-8"
                        android:valueTo="0" />
                </set>
            </aapt:attr>
        </target>
    
    </animated-vector>
    
    

    闹钟“振铃”动画就是这么简单。

    2.3 单选按钮选择效果

    单选按钮选择效果.gif

    该图标仅使用两条路径绘制:填充的内点和描边的外圈。当单选按钮在未选中状态到选中状态之间转换时,将为三个属性设置动画:

    首先我们看看单选按钮这个图片如何“画”出来。
    老样子,打开https://material.io/resources/icons/?search=radio_button_checked&icon=radio_button_checked&style=baseline
    下载选中后的图svg路径,根据上面动画效果显示,需要一个未选图片,即使中心是空的,然后还有一个选中后的图片,代码如下:

    <!-- 未选图片 -->
    <vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="24dp"
        android:height="24dp"
        android:tint="?attr/colorControlNormal"
        android:viewportWidth="24"
        android:viewportHeight="24">
        <!-- 外圈,pivotX和pivotY都设置12中心点,这样围绕着中心点放大或者缩小 -->
        <group
            android:name="ring_outer"
            android:pivotX="12"
            android:pivotY="12">
            <path
                android:name="ring_outer_path"
                android:pathData="M 12 2 C 6.48 2 2 6.48 2 12 C 2 17.52 6.48 22 12 22 C 17.52 22 22 17.52 22 12 C 22 6.48 17.52 2 12 2 Z"
                android:strokeWidth="2"
                android:strokeColor="@android:color/white" />
        </group>
        <!-- 内圈,pivotX和pivotY都设置12中心点,这样围绕着中心点放大或者缩小。scaleX和scaleY都设置0去掉内圈 -->
        <group
            android:name="dot_group"
            android:pivotX="12"
            android:pivotY="12"
            android:scaleX="0"
            android:scaleY="0">
            <path
                android:name="dot_path"
                android:fillColor="@android:color/white"
                android:pathData="M 12 7 C 9.24 7 7 9.24 7 12 C 7 14.76 9.24 17 12 17 C 14.76 17 17 14.76 17 12 C 17 9.24 14.76 7 12 7 Z" />
        </group>
    </vector>
    
    
    
    <!-- 已选图片 -->
    <vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="24dp"
        android:height="24dp"
        android:tint="?attr/colorControlNormal"
        android:viewportWidth="24"
        android:viewportHeight="24">
        <!-- 外环,pivotX和pivotY都设置12中心点,这样围绕着中心点放大或者缩小 -->
        <group
            android:name="ring_outer"
            android:pivotX="12"
            android:pivotY="12">
            <path
                android:name="ring_outer_path"
                android:pathData="M 12 2 C 6.48 2 2 6.48 2 12 C 2 17.52 6.48 22 12 22 C 17.52 22 22 17.52 22 12 C 22 6.48 17.52 2 12 2 Z"
                android:strokeWidth="2"
                android:strokeColor="@android:color/white" />
        </group>
        <!-- 内圈,pivotX和pivotY都设置12中心点,这样围绕着中心点放大或者缩小 -->
        <group
            android:name="dot_group"
            android:pivotX="12"
            android:pivotY="12">
            <path
                android:name="dot_path"
                android:fillColor="@android:color/white"
                android:pathData="M 12 7 C 9.24 7 7 9.24 7 12 C 7 14.76 9.24 17 12 17 C 14.76 17 17 14.76 17 12 C 17 9.24 14.76 7 12 7 Z" />
        </group>
    </vector>
    
    

    接下来是个过渡动画

    <?xml version="1.0" encoding="utf-8"?>
    <animated-selector xmlns:android="http://schemas.android.com/apk/res/android">
    
      <!-- 选中的图片 -->
      <item
        android:id="@+id/checked"
        android:drawable="@drawable/vd_checkable_radiobutton_checked"
        android:state_checked="true"/>
    
      <!-- 未选的图片 -->
      <item
        android:id="@+id/unchecked"
        android:drawable="@drawable/vd_checkable_radiobutton_unchecked"/>
    
      <!-- 从未选过渡到选中的动画 -->
      <transition
        android:drawable="@drawable/avd_checkable_radiobutton_unchecked_to_checked"
        android:fromId="@id/unchecked"
        android:toId="@id/checked"/>
    
      <!-- 从选中过渡到未选的动画 -->
      <transition
        android:drawable="@drawable/avd_checkable_radiobutton_checked_to_unchecked"
        android:fromId="@id/checked"
        android:toId="@id/unchecked"/>
    
    </animated-selector>
    
    <!-- 从未选过渡到选中的动画 -->
    <animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:aapt="http://schemas.android.com/aapt"
        android:drawable="@drawable/vd_checkable_radiobutton_unchecked">
        <!-- 外圈的动画 -->
        <target android:name="ring_outer">
            <aapt:attr name="android:animation">
                <set>
                    <!-- 标记顺序执行动画 -->
                    <set android:ordering="sequentially">
                        <objectAnimator
                            android:duration="166"
                            android:interpolator="@android:interpolator/fast_out_slow_in"
                            android:propertyName="scaleX"
                            android:valueFrom="1.0"
                            android:valueTo="0.5"
                            android:valueType="floatType" />
                        <objectAnimator
                            android:duration="16"
                            android:interpolator="@android:interpolator/fast_out_slow_in"
                            android:propertyName="scaleX"
                            android:valueFrom="0.5"
                            android:valueTo="0.9"
                            android:valueType="floatType" />
                        <objectAnimator
                            android:duration="316"
                            android:interpolator="@android:interpolator/fast_out_slow_in"
                            android:propertyName="scaleX"
                            android:valueFrom="0.9"
                            android:valueTo="1.0"
                            android:valueType="floatType" />
                    </set>
                    <set android:ordering="sequentially">
                        <objectAnimator
                            android:duration="166"
                            android:interpolator="@android:interpolator/fast_out_slow_in"
                            android:propertyName="scaleY"
                            android:valueFrom="1.0"
                            android:valueTo="0.5"
                            android:valueType="floatType" />
                        <objectAnimator
                            android:duration="16"
                            android:interpolator="@android:interpolator/fast_out_slow_in"
                            android:propertyName="scaleY"
                            android:valueFrom="0.5"
                            android:valueTo="0.9"
                            android:valueType="floatType" />
                        <objectAnimator
                            android:duration="316"
                            android:interpolator="@android:interpolator/fast_out_slow_in"
                            android:propertyName="scaleY"
                            android:valueFrom="0.9"
                            android:valueTo="1.0"
                            android:valueType="floatType" />
                    </set>
                </set>
            </aapt:attr>
        </target>
        <!-- 外圈的路径 -->
        <target android:name="ring_outer_path">
            <aapt:attr name="android:animation">
                <set>
                    <set android:ordering="sequentially">
                        <objectAnimator
                            android:duration="166"
                            android:interpolator="@anim/checkable_radiobutton"
                            android:propertyName="strokeWidth"
                            android:valueFrom="2.0"
                            android:valueTo="18.0"
                            android:valueType="floatType" />
                        <objectAnimator
                            android:duration="16"
                            android:interpolator="@android:interpolator/fast_out_slow_in"
                            android:propertyName="strokeWidth"
                            android:valueFrom="18.0"
                            android:valueTo="2.0"
                            android:valueType="floatType" />
                        <objectAnimator
                            android:duration="316"
                            android:interpolator="@android:interpolator/fast_out_slow_in"
                            android:propertyName="strokeWidth"
                            android:valueFrom="2.0"
                            android:valueTo="2.0"
                            android:valueType="floatType" />
                    </set>
                </set>
            </aapt:attr>
        </target>
        <!-- 内点的动画 -->
        <target android:name="dot_group">
            <aapt:attr name="android:animation">
                <set>
                    <set android:ordering="sequentially">
                        <objectAnimator
                            android:duration="166"
                            android:interpolator="@android:interpolator/fast_out_slow_in"
                            android:propertyName="scaleX"
                            android:valueFrom="0.0"
                            android:valueTo="0.0"
                            android:valueType="floatType" />
                        <objectAnimator
                            android:duration="16"
                            android:interpolator="@android:interpolator/fast_out_slow_in"
                            android:propertyName="scaleX"
                            android:valueFrom="0.0"
                            android:valueTo="1.5"
                            android:valueType="floatType" />
                        <objectAnimator
                            android:duration="316"
                            android:interpolator="@android:interpolator/fast_out_slow_in"
                            android:propertyName="scaleX"
                            android:valueFrom="1.5"
                            android:valueTo="1.0"
                            android:valueType="floatType" />
                    </set>
                    <set android:ordering="sequentially">
                        <objectAnimator
                            android:duration="166"
                            android:interpolator="@android:interpolator/fast_out_slow_in"
                            android:propertyName="scaleY"
                            android:valueFrom="0.0"
                            android:valueTo="0.0"
                            android:valueType="floatType" />
                        <objectAnimator
                            android:duration="16"
                            android:interpolator="@android:interpolator/fast_out_slow_in"
                            android:propertyName="scaleY"
                            android:valueFrom="0.0"
                            android:valueTo="1.5"
                            android:valueType="floatType" />
                        <objectAnimator
                            android:duration="316"
                            android:interpolator="@android:interpolator/fast_out_slow_in"
                            android:propertyName="scaleY"
                            android:valueFrom="1.5"
                            android:valueTo="1.0"
                            android:valueType="floatType" />
                    </set>
                </set>
            </aapt:attr>
        </target>
    </animated-vector>
    
    
    <!-- 从选中过渡到未选的动画 -->
    <animated-vector
      xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:aapt="http://schemas.android.com/aapt"
      android:drawable="@drawable/vd_checkable_radiobutton_checked">
      <!-- 外圈的动画 -->
      <target android:name="ring_outer">
        <aapt:attr name="android:animation">
          <set>
            <set android:ordering="sequentially">
              <objectAnimator
                android:duration="183"
                android:interpolator="@android:interpolator/fast_out_slow_in"
                android:propertyName="scaleX"
                android:valueFrom="1.0"
                android:valueTo="0.9"
                android:valueType="floatType"/>
              <objectAnimator
                android:duration="16"
                android:interpolator="@anim/checkable_radiobutton"
                android:propertyName="scaleX"
                android:valueFrom="0.9"
                android:valueTo="0.5"
                android:valueType="floatType"/>
              <objectAnimator
                android:duration="300"
                android:interpolator="@anim/checkable_radiobutton"
                android:propertyName="scaleX"
                android:valueFrom="0.5"
                android:valueTo="1.0"
                android:valueType="floatType"/>
            </set>
            <set android:ordering="sequentially">
              <objectAnimator
                android:duration="183"
                android:interpolator="@android:interpolator/fast_out_slow_in"
                android:propertyName="scaleY"
                android:valueFrom="1.0"
                android:valueTo="0.9"
                android:valueType="floatType"/>
              <objectAnimator
                android:duration="16"
                android:interpolator="@anim/checkable_radiobutton"
                android:propertyName="scaleY"
                android:valueFrom="0.9"
                android:valueTo="0.5"
                android:valueType="floatType"/>
              <objectAnimator
                android:duration="300"
                android:interpolator="@anim/checkable_radiobutton"
                android:propertyName="scaleY"
                android:valueFrom="0.5"
                android:valueTo="1.0"
                android:valueType="floatType"/>
            </set>
          </set>
        </aapt:attr>
      </target>
      <!-- 外圈的路径 -->
      <target android:name="ring_outer_path">
        <aapt:attr name="android:animation">
          <set>
            <set android:ordering="sequentially">
              <objectAnimator
                android:duration="183"
                android:interpolator="@android:interpolator/fast_out_slow_in"
                android:propertyName="strokeWidth"
                android:valueFrom="2.0"
                android:valueTo="2.0"
                android:valueType="floatType"/>
              <objectAnimator
                android:duration="16"
                android:interpolator="@android:interpolator/fast_out_slow_in"
                android:propertyName="strokeWidth"
                android:valueFrom="2.0"
                android:valueTo="18.0"
                android:valueType="floatType"/>
              <objectAnimator
                android:duration="300"
                android:interpolator="@android:interpolator/fast_out_slow_in"
                android:propertyName="strokeWidth"
                android:valueFrom="18.0"
                android:valueTo="2.0"
                android:valueType="floatType"/>
            </set>
          </set>
        </aapt:attr>
      </target>
      <!-- 内点的动画 -->
      <target android:name="dot_group">
        <aapt:attr name="android:animation">
          <set>
            <set android:ordering="sequentially">
              <objectAnimator
                android:duration="183"
                android:interpolator="@android:interpolator/fast_out_slow_in"
                android:propertyName="scaleX"
                android:valueFrom="1.0"
                android:valueTo="1.4"
                android:valueType="floatType"/>
              <objectAnimator
                android:duration="16"
                android:interpolator="@android:interpolator/fast_out_slow_in"
                android:propertyName="scaleX"
                android:valueFrom="1.4"
                android:valueTo="0.0"
                android:valueType="floatType"/>
              <objectAnimator
                android:duration="300"
                android:interpolator="@android:interpolator/fast_out_slow_in"
                android:propertyName="scaleX"
                android:valueFrom="0.0"
                android:valueTo="0.0"
                android:valueType="floatType"/>
            </set>
            <set android:ordering="sequentially">
              <objectAnimator
                android:duration="183"
                android:interpolator="@android:interpolator/fast_out_slow_in"
                android:propertyName="scaleY"
                android:valueFrom="1.0"
                android:valueTo="1.4"
                android:valueType="floatType"/>
              <objectAnimator
                android:duration="16"
                android:interpolator="@android:interpolator/fast_out_slow_in"
                android:propertyName="scaleY"
                android:valueFrom="1.4"
                android:valueTo="0.0"
                android:valueType="floatType"/>
              <objectAnimator
                android:duration="300"
                android:interpolator="@android:interpolator/fast_out_slow_in"
                android:propertyName="scaleY"
                android:valueFrom="0.0"
                android:valueTo="0.0"
                android:valueType="floatType"/>
            </set>
          </set>
        </aapt:attr>
      </target>
    </animated-vector>
    

    选择过渡动画原理也是很简单,通过内圆和外圆不断的放大,缩小造成视觉差的效果。

    2.4 线性进度加载效果

    线性进度加载效果.gif

    由三个路径组成:半透明背景和两个内部矩形路径。 在动画期间,两个内部矩形会水平平移并以不同程度缩放。下面的xml以图片和动画一起。

    <animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:aapt="http://schemas.android.com/aapt">
    
        <aapt:attr name="android:drawable">
            <!-- 这是一个宽度360dp,高度10dp的画布 -->
            <vector
                android:width="360dp"
                android:height="10dp"
                android:viewportWidth="360"
                android:viewportHeight="10">
                <!-- 这个group挪到translateX180,translateY5即是画布的中间 -->
                <group
                    android:name="progress_group"
                    android:translateX="180"
                    android:translateY="5">
                    <path
                        android:name="background_track"
                        android:fillAlpha="?android:attr/disabledAlpha"
                        android:fillColor="?attr/colorControlActivated"
                        android:pathData="M -180 -1 L 180 -1 L 180 1 L -180 1 Z" />
                    <!-- 调用了下面的rect2_grp -->
                    <group
                        android:name="rect2_grp"
                        android:scaleX="0.1"
                        android:translateX="-197.60001">
                        <path
                            android:name="rect2"
                            android:fillColor="?attr/colorControlActivated"
                            android:pathData="M -144 -1 L 144 -1 L 144 1 L -144 1 Z" />
                    </group>
                    <!-- 调用了下面的rect1_grp -->
                    <group
                        android:name="rect1_grp"
                        android:scaleX="0.1"
                        android:translateX="-522.59998">
                        <path
                            android:name="rect1"
                            android:fillColor="?attr/colorControlActivated"
                            android:pathData="M -144 -1 L 144 -1 L 144 1 L -144 1 Z" />
                    </group>
                </group>
            </vector>
        </aapt:attr>
    
        <!-- 在改变translateX的同时修改scaleX缩放 -->
        <target android:name="rect2_grp">
            <aapt:attr name="android:animation">
                <set>
                    <objectAnimator
                        android:duration="2000"
                        android:pathData="M -197.60001,0 c 14.28182,0 85.07782,0 135.54689,0 c 54.26191,0 90.42461,0 168.24331,0 c 144.72154,0 316.40982,0 316.40982,0"
                        android:propertyXName="translateX"
                        android:repeatCount="infinite">
                        <!-- 运动轨迹 -->
                        <aapt:attr name="android:interpolator">
                            <pathInterpolator android:pathData="M 0,0 C 0.0375,0 0.128764607715,0.0895380946618 0.25,0.218553507947 C 0.322410320025,0.295610602487 0.436666666667,0.417591408114 0.483333333333,0.489826169306 C 0.69,0.80972296795 0.793333333333,0.950016125212 1,1 " />
                        </aapt:attr>
                    </objectAnimator>
                    <objectAnimator
                        android:duration="2000"
                        android:pathData="M 0,0.1 L 1,0.571379510698 L 2,0.909950256348 L 3,0.1"
                        android:propertyYName="scaleX"
                        android:repeatCount="infinite">
                        <!-- 运动轨迹 -->
                        <aapt:attr name="android:interpolator">
                            <pathInterpolator android:pathData="M 0,0 C 0.06834272400867,0.01992566661414 0.19220331656133,0.15855429260523 0.33333333333333,0.34926160892842 C 0.38410433133433,0.41477913453861 0.54945792615267,0.68136029463551 0.66666666666667,0.68279962777002 C 0.752586273196,0.68179620963216 0.737253971954,0.878896194318 1,1" />
                        </aapt:attr>
                    </objectAnimator>
                </set>
    
            </aapt:attr>
        </target>
    
        <!-- 在改变translateX的同时修改scaleX缩放 -->
        <target android:name="rect1_grp">
            <aapt:attr name="android:animation">
                <set>
                    <objectAnimator
                        android:duration="2000"
                        android:pathData="M -522.59998,0 c 48.89972,0 166.02656,0 301.21729,0 c 197.58128,0 420.9827,0 420.9827,0"
                        android:propertyXName="translateX"
                        android:repeatCount="infinite">
                        <!-- 运动轨迹 -->
                        <aapt:attr name="android:interpolator">
                            <pathInterpolator android:pathData="M 0,0 L 0.2 0 C 0.3958333333336,0 0.474845090492,0.206797621729 0.5916666666664,0.417082932942 C 0.7151610251224,0.639379624869 0.81625,0.974556908664 1,1" />
                        </aapt:attr>
                    </objectAnimator>
                    <objectAnimator
                        android:duration="2000"
                        android:pathData="M 0 0.1 L 1 0.826849212646 L 2 0.1"
                        android:propertyYName="scaleX"
                        android:repeatCount="infinite">
                        <!-- 运动轨迹 -->
                        <aapt:attr name="android:interpolator">
                            <pathInterpolator android:pathData="M 0 0 L 0.3665 0 C 0.47252618112021,0.062409910275 0.61541608570164,0.5 0.68325,0.5 C 0.75475061236836,0.5 0.75725829093844,0.814510098964 1,1" />
                        </aapt:attr>
                    </objectAnimator>
                </set>
    
            </aapt:attr>
        </target>
    
    </animated-vector>
    
    



    那么该章节系列到此结束,以下是4个demo的相关地址
    放大/旋转/移动 转换各例子
    展开折叠效果
    单选按钮选择效果
    线性进度加载效果

    相关文章

      网友评论

        本文标题:svg Vector 章节(2):绘制图形并改变groups p

        本文链接:https://www.haomeiwen.com/subject/pqzopctx.html