Android AnimatedVectorDrawable
在本教程中,我们将讨论AnimatedVectorDrawable并在我们的android应用程序中以各种方式实现它。
了解VectorDrawables将使下面的文章更容易理解。
AnimatedVectorDrawable
自API 21以来就引入了AnimatedVectorDrawable类,该类可用于轻松漂亮地对Vector Drawables进行动画处理。
以下是您可以使用AnimatedVectorDrawable执行的一些操作:
旋转,缩放,平移VectorDrawables
对VectorDrawable进行动画处理,例如填充颜色等。
绘制路径并进行路径变形
通常,要为Vector Drawable设置动画,我们使用ObjectAnimator类定义动画。
ShapeShifter是一种流行的工具,可以直观地创建AnimatedVectorDrawable。
为此,我们需要导入Vector Asset/SVG文件。
我们有一个名为ic_settings.xml的示例矢量可绘制xml文件,如下所示:
<vector android:height="24dp" android:tint="#E5496D" android:viewportHeight="24.0" android:viewportWidth="24.0" android:width="24dp" xmlns:android="https://schemas.android.com/apk/res/android"> <path android:fillColor="#FF000000" android:pathData="M19.43,12.98c0.04,-0.32 0.07,-0.64 0.07,-0.98s-0.03,-0.66 -0.07,-0.98l2.11,-1.65c0.19,-0.15 0.24,-0.42 0.12,-0.64l-2,-3.46c-0.12,-0.22 -0.39,-0.3 -0.61,-0.22l-2.49,1c-0.52,-0.4 -1.08,-0.73 -1.69,-0.98l-0.38,-2.65C14.46,2.18 14.25,2 14,2h-4c-0.25,0 -0.46,0.18 -0.49,0.42l-0.38,2.65c-0.61,0.25 -1.17,0.59 -1.69,0.98l-2.49,-1c-0.23,-0.09 -0.49,0 -0.61,0.22l-2,3.46c-0.13,0.22 -0.07,0.49 0.12,0.64l2.11,1.65c-0.04,0.32 -0.07,0.65 -0.07,0.98s0.03,0.66 0.07,0.98l-2.11,1.65c-0.19,0.15 -0.24,0.42 -0.12,0.64l2,3.46c0.12,0.22 0.39,0.3 0.61,0.22l2.49,-1c0.52,0.4 1.08,0.73 1.69,0.98l0.38,2.65c0.03,0.24 0.24,0.42 0.49,0.42h4c0.25,0 0.46,-0.18 0.49,-0.42l0.38,-2.65c0.61,-0.25 1.17,-0.59 1.69,-0.98l2.49,1c0.23,0.09 0.49,0 0.61,-0.22l2,-3.46c0.12,-0.22 0.07,-0.49 -0.12,-0.64l-2.11,-1.65zM12,15.5c-1.93,0 -3.5,-1.57 -3.5,-3.5s1.57,-3.5 3.5,-3.5 3.5,1.57 3.5,3.5 -1.57,3.5 -3.5,3.5z" </vector>
让我们将其导入ShapeShifter中以创建AnimatedVectorDrawable:
首先,我们需要在组图层中添加矢量drawable以便向其中添加动画。
我们将可绘制矢量设置为旋转270度。
您必须设置VectorDrawable将围绕其旋转的ivotX和pivotY。
VectorDrawable的背景颜色并非总是正确地导入ShapeShifter中。
因此,您需要在此处再次设置。
以下是可以在AnimatedVectorDrawable上设置的一些属性:
- 回转
- X轴
- 枢轴
- 标度X
- 比例尺
- 翻译X
- 翻译
- pathData
- 填色
- strokeColor
- strokeWidth
- 笔画
- fillAlpha
- trimPathStart
- trimPathEnd
- trimPathOffset
现在,从ShapeShifter中,单击"导出– AnimatedVectorDrawable"以生成AnimatedVectorDrawable的xml版本:
ʻavd_settings.xml`
<animated-vector xmlns:android="https://schemas.android.com/apk/res/android" xmlns:aapt="https://schemas.android.com/aapt"> <aapt:attr name="android:drawable"> <vector android:name="settings_icon" android:width="48dp" android:height="48dp" android:viewportHeight="24" android:viewportWidth="24"> <group android:name="animate_vector"> <path android:name="gear" android:fillColor="#FF000000" android:pathData="@string/settings_path" </group> </vector> </aapt:attr> <target android:name="animate_vector"> <aapt:attr name="android:animation"> <set> <objectAnimator android:duration="800" android:interpolator="@android:anim/accelerate_decelerate_interpolator" android:propertyName="rotation" android:repeatCount="infinite" android:repeatMode="restart" android:valueFrom="0" android:valueTo="270" android:valueType="floatType" <objectAnimator android:duration="800" android:interpolator="@android:interpolator/fast_out_slow_in" android:propertyName="pivotX" android:valueFrom="12" android:valueTo="12" android:valueType="floatType" <objectAnimator android:duration="800" android:interpolator="@android:interpolator/fast_out_slow_in" android:propertyName="pivotY" android:valueFrom="12" android:valueTo="12" android:valueType="floatType" </set> </aapt:attr> </target> </animated-vector>
我们已在strings.xml文件中将长路径数据设置为字符串资源。
AnimatedVectorDrawable中的" target"元素的name属性对应于动画组的名称。
animation属性采用了animator类,在此是对象animator。
为了使AnimatedVectorDrawable永久动画,我们在ObjectAnimator标记中为无限添加了repeatCount。
现在我们有了AnimatedVectorDrawable,我们可以通过以下方法在ImageView(任何相关视图)上进行设置:ʻandroid:src =" @ drawable/avd_settings""。
仍可绘制动画的矢量可绘制动画!
为了使其具有动画效果,我们需要执行以下操作:
Animatable animatable = imageView.getDrawable(); animatable.start();
动画表是一个接口,其中包含处理可绘制对象上的动画的方法。
像–start()
,stop()
,isRunning()
之类的方法
以编程方式设置AnimatedVectorDrawable
AnimatedVectorDrawableCompat animatedVectorDrawableCompat = AnimatedVectorDrawableCompat.create(this, R.drawable.avd_settings); imageView.setImageDrawable(animatedVectorDrawableCompat);
这是上下文。
除了可以在单个xml文件中创建可绘制的整个动画矢量之外,我们还可以分别设置对象或者动画制作者。
在以下部分中,我们将创建不同类型的AnimatedVectorDrawable
项目结构
不要忘记在应用的build.gradle中启用向量支持:
android { ... defaultConfig { ... vectorDrawables.useSupportLibrary = true ... } ... }
代码
下面给出了activity_main.xml布局的代码:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="https://schemas.android.com/apk/res/android" xmlns:app="https://schemas.android.com/apk/res-auto" xmlns:tools="https://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:orientation="vertical" tools:context=".MainActivity"> <ImageView android:id="@+id/imgSettings" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_margin="4dp" app:srcCompat="@drawable/avd_settings" <android.support.design.widget.FloatingActionButton android:id="@+id/fabSync" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="4dp" android:backgroundTint="@android:color/white" <ImageView android:id="@+id/imgJD" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_margin="4dp" app:srcCompat="@drawable/avd_jd" <android.support.design.widget.FloatingActionButton android:id="@+id/fabTickCross" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:backgroundTint="@android:color/white" android:src="@drawable/ic_tick" </LinearLayout>
我们已经看过avd_settings.xml文件。
接下来看avd_jd.xml。
我们编写的ic_jd.xml是:
<?xml version="1.0" encoding="utf-8"?> <vector xmlns:android="https://schemas.android.com/apk/res/android" android:width="48dp" android:height="48dp" android:viewportHeight="48.0" android:viewportWidth="48.0"> <group android:name="thing"> <path android:name="Dev" android:pathData="M 25 10 L 12 10 M 25 10 L 25 30 M 25 30 C 20 35 15 30 12 25" android:strokeColor="#000" android:strokeWidth="1" <path android:name="Journal" android:pathData="M 30 10 L 30 30 M 30 10 C 45 15 45 25 30 30" android:strokeColor="@android:color/holo_red_dark" android:strokeWidth="1" </group> </vector>
从ShapeShifter生成的avd_jd.xml代码为:
<animated-vector xmlns:android="https://schemas.android.com/apk/res/android" xmlns:aapt="https://schemas.android.com/aapt"> <aapt:attr name="android:drawable"> <vector android:name="vector" android:width="148dp" android:height="148dp" android:viewportWidth="48" android:viewportHeight="48"> <group android:name="theitroad"> <group android:name="group_j" android:pivotX="24" android:pivotY="24" android:rotation="270"> <path android:name="journal" android:pathData="M 25 10 L 12 10 M 25 10 L 25 30 M 25 30 C 20 35 15 30 12 25" android:strokeColor="#000000" android:strokeWidth="1" </group> </group> <group android:name="group_d" android:pivotX="24" android:pivotY="24" android:translateX="10" android:scaleX="0.5" android:scaleY="0.5"> <path android:name="dev" android:pathData="M 30 10 L 30 30 M 30 10 C 45 15 45 25 30 30" android:strokeColor="#000000" android:strokeWidth="1" </group> </vector> </aapt:attr> <target android:name="group_d"> <aapt:attr name="android:animation"> <set> <objectAnimator android:propertyName="translateX" android:duration="400" android:valueFrom="10" android:valueTo="0" android:valueType="floatType" android:interpolator="@android:interpolator/fast_out_slow_in" <objectAnimator android:propertyName="scaleX" android:duration="600" android:valueFrom="0.5" android:valueTo="1" android:valueType="floatType" android:interpolator="@android:interpolator/fast_out_slow_in" <objectAnimator android:propertyName="scaleY" android:duration="600" android:valueFrom="0.5" android:valueTo="1" android:valueType="floatType" android:interpolator="@android:interpolator/fast_out_slow_in" </set> </aapt:attr> </target> <target android:name="group_j"> <aapt:attr name="android:animation"> <objectAnimator android:propertyName="rotation" android:startOffset="100" android:duration="500" android:valueFrom="270" android:valueTo="0" android:valueType="floatType" android:interpolator="@android:interpolator/fast_out_slow_in" </aapt:attr> </target> <target android:name="journal"> <aapt:attr name="android:animation"> <objectAnimator android:propertyName="strokeColor" android:startOffset="600" android:duration="200" android:valueFrom="#000000" android:valueTo="#cc0000" android:valueType="colorType" android:interpolator="@android:interpolator/fast_out_slow_in" </aapt:attr> </target> </animated-vector>
在上面的XML代码中,我们分别在两条路径上进行了缩放,动画和旋转。
注意,每个路径都有一个name属性,该属性链接到各自的目标。
XML属性是不言自明的。
一旦掌握了这些,就可以直接编写AnimatedVectorDrawable XML代码,而无需使用ShapeShifter。
avd_cross2tick.xml和avd_tick2cross.xml用于将可绘制的刻度线向量转换为可绘制的交叉向量。
因此,它改变了路径。
对象动画师的代码分别放在res目录中的动画师文件夹中。
您可以在本教程结尾的源代码/Github存储库中找到它们的完整实现。
由于篇幅所限,我们忽略了这一点。
MainActivity.java的代码如下:
package com.theitroad.androidanimatedvectordrawable; import android.graphics.drawable.Animatable; import android.graphics.drawable.Animatable2; import android.graphics.drawable.AnimatedVectorDrawable; import android.graphics.drawable.Drawable; import android.os.Build; import android.support.design.widget.FloatingActionButton; import android.support.graphics.drawable.AnimatedVectorDrawableCompat; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.ImageView; public class MainActivity extends AppCompatActivity implements View.OnClickListener { private AnimatedVectorDrawable tickToCross, crossToTick; private boolean isTick = true; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); FloatingActionButton fabSync = findViewById(R.id.fabSync); FloatingActionButton fabTickCross = findViewById(R.id.fabTickCross); tickToCross = (AnimatedVectorDrawable) getDrawable(R.drawable.avd_tick2cross); crossToTick = (AnimatedVectorDrawable) getDrawable(R.drawable.avd_cross2tick); ImageView imgSettings = findViewById(R.id.imgSettings); ImageView imgJD = findViewById(R.id.imgJD); imgSettings.setOnClickListener(this); imgJD.setOnClickListener(this); AnimatedVectorDrawableCompat animatedVectorDrawableCompat = AnimatedVectorDrawableCompat.create(this, R.drawable.avd_sync); fabSync.setImageDrawable(animatedVectorDrawableCompat); fabSync.setOnClickListener(this); fabTickCross.setOnClickListener(this); } @Override public void onClick(View view) { switch (view.getId()) { case R.id.imgSettings: Animatable animatable = (Animatable) ((ImageView) view).getDrawable(); if (animatable.isRunning()) animatable.stop(); else animatable.start(); break; case R.id.imgJD: animatable = (Animatable) ((ImageView) view).getDrawable(); if (animatable.isRunning()) animatable.stop(); else animatable.start(); break; case R.id.fabSync: animatable = (Animatable) ((FloatingActionButton) view).getDrawable(); if (animatable.isRunning()) animatable.stop(); else animatable.start(); break; case R.id.fabTickCross: AnimatedVectorDrawable drawable = isTick ? tickToCross : crossToTick; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { drawable.registerAnimationCallback(new Animatable2.AnimationCallback() { @Override public void onAnimationStart(Drawable drawable) { super.onAnimationStart(drawable); } @Override public void onAnimationEnd(Drawable drawable) { super.onAnimationEnd(drawable); } }); } FloatingActionButton fab = ((FloatingActionButton) view); fab.setImageDrawable(drawable); drawable.start(); isTick = !isTick; break; } } }
其中我们在两个ImageView和两个FloatingActionButtons上设置了AnimatedVectorDrawable。
为了收听动画的开始和结束,我们可以在AnimatedVectorDrawable上注册动画回调:
drawable.registerAnimationCallback(new Animatable2.AnimationCallback() { @Override public void onAnimationStart(Drawable drawable) { super.onAnimationStart(drawable); } @Override public void onAnimationEnd(Drawable drawable) { super.onAnimationEnd(drawable); } });
注意:registerAnimationCallback
仅适用于Android M(23)及更高版本。