动画分为视图动画和属性动画框架。
- 视图动画:
- 提供AlphaAnimation、RotateAnimation、TranslateAnimation、ScaleAnimation四种动画方式
- 提供动画合集AnimationSet,用于动画混合
- 缺点显著:不具备交互性,只能做普通的动画效果
- 优点:效率高、使用方便
- 属性动画框架:更加丰富的动画效果。
常见问题
- 视图动画和属性动画优缺点
- 视图动画的使用
- 属性动画的使用
- ObjectAnimator、AnimatorSet、PropertyValuesHolder、ValueAnimator的作用
- 如何利用xml使用属性动画
- 动画事件有哪些?
- 布局动画是什么?
- 插值器Interpolators的作用
- SVG是什么?
- SVG和Bitmap的区别
- 如何在Android中使用SVG(VectorDrawable和VectorDrawable)?
1-视图动画实例
展现4种动画效果
1-布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:layout_weight="3"
tools:context="com.example.administrator.featherdemos.Activity.AnimationSetActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:orientation="horizontal"
android:layout_weight="1"
android:weightSum="2">
<ImageView
android:id="@+id/animationset_imageview1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:src="@drawable/jide"
android:layout_weight="1"
android:layout_centerInParent="true"/>
<ImageView
android:id="@+id/animationset_imageview2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:src="@drawable/jide"
android:layout_weight="1"
android:layout_centerInParent="true"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:orientation="horizontal"
android:layout_weight="1"
android:weightSum="2">
<ImageView
android:id="@+id/animationset_imageview3"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:src="@drawable/jide"
android:layout_weight="1"
android:layout_centerInParent="true"/>
<ImageView
android:id="@+id/animationset_imageview4"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:src="@drawable/jide"
android:layout_weight="1"
android:layout_centerInParent="true"/>
</LinearLayout>
<ImageView
android:id="@+id/animationset_set_imageview"
android:layout_width="match_parent"
android:layout_height="0dp"
android:src="@drawable/jide"
android:layout_weight="1"
/>
</LinearLayout>
2-Activity
public class AnimationSetActivity extends Activity {
ImageView imageView1;
ImageView imageView2;
ImageView imageView3;
ImageView imageView4;
ImageView imageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_animation_set);
imageView1 = (ImageView) findViewById(R.id.animationset_imageview1);
imageView2 = (ImageView) findViewById(R.id.animationset_imageview2);
imageView3 = (ImageView) findViewById(R.id.animationset_imageview3);
imageView4 = (ImageView) findViewById(R.id.animationset_imageview4);
imageView = (ImageView) findViewById(R.id.animationset_set_imageview);
//透明度
AlphaAnimation alphaAnimation = new AlphaAnimation(0, 1);
alphaAnimation.setDuration(2000);
imageView1.setAnimation(alphaAnimation);
//旋转
RotateAnimation rotateAnimation = new RotateAnimation(0, 10);
rotateAnimation.setDuration(2000);
imageView2.setAnimation(rotateAnimation);
//缩放
ScaleAnimation scaleAnimation = new ScaleAnimation(0.5f, 1, 0.5f, 1);
scaleAnimation.setDuration(2000);
imageView3.setAnimation(scaleAnimation);
//平移
TranslateAnimation translateAnimation = new TranslateAnimation(0, 50, 0, 50);
translateAnimation.setDuration(2000);
imageView4.setAnimation(translateAnimation);
/*
* 动画集合,可以混合多种动画效果。
* */
AnimationSet animationSet = new AnimationSet(true);
animationSet.setDuration(3000);
animationSet.addAnimation(alphaAnimation);
animationSet.addAnimation(rotateAnimation);
imageView.setAnimation(animationSet);
}
}
2-属性动画
Animator框架中最多的就是AnimatorSet和ObjectAnimator。ObjectAnimator控制一个对象的一个属性,将多个ObjectAnimator组合成AnimatorSet形成动画。
属性值 | 作用 |
---|---|
translationX、translationY | 控制View从左上角偏移的位置 |
rotation、rotationX、rotationY | 控制View围绕支点做2D和3D旋转 |
scaleX、scaleY | 围绕支点2D缩放 |
pivotX、pivotY | 控制支点位置,默认为View中心 |
x、y | 描述View的最终位置 |
alpha | 透明度,默认1不透明,0为完全透明 |
- 要操作的View的属性,必须要有get和set方法。
- 如果没有get、set方法,需要使用装饰者模式包装获得get、set;或者通过后面的ValueAnimator实现。
1-实例
ImageView imageView = (ImageView) findViewById(R.id.animator_imageview);
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(imageView,
"translationY", 300);
objectAnimator.setDuration(2000);
objectAnimator.start();
2-没有get、set方法
实现包装类
private class WrapperView{
private View view;
public WrapperView(View view){
this.view = view;
}
public int getWidth(){
return view.getLayoutParams().width;
}
public void setWidth(int width){
view.getLayoutParams().width = width;
view.requestLayout();
}
}
使用包装类实现属性动画
WrapperView wrapperView = new WrapperView(imageView);
ObjectAnimator.ofInt(wrapperView, "width", 500).setDuration(2000).start();
3-PropertyValuesHolder
类似于AnimationSet的作用,将多种效果共同作用于对象。
PropertyValuesHolder pvh1 = PropertyValuesHolder.ofFloat("translationY", 200);
PropertyValuesHolder pvh2 = PropertyValuesHolder.ofFloat("scaleX", 1f, 0, 1f);
PropertyValuesHolder pvh3 = PropertyValuesHolder.ofFloat("scaleY", 1f, 0, 1f);
ObjectAnimator.ofPropertyValuesHolder(imageView, pvh1, pvh2, pvh3).setDuration(1000).start();
4-ValueAnimator
ObjectAnimator的父类,提供数值变化和监听,本身不完成动画,通过得到的数值可以去进行一定变换。
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 100);
valueAnimator.setTarget(imageView);
valueAnimator.setDuration(1000);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
Float value = (Float) valueAnimator.getAnimatedValue();
//使用数值去完成数值的变换
}
});
1-实例:数字自动增加(0~100)
TextView textView = (TextView) findViewById(R.id.count_textview);
textView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//数值动画从0~100增长
ValueAnimator valueAnimator = ValueAnimator.ofInt(0, 100);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
//使用获取的数值,显示在TextView(数值自动增长)
textView.setText((Integer) valueAnimator.getAnimatedValue()+"");
}
});
//动画在3s内完成
valueAnimator.setDuration(3000);
valueAnimator.start();
}
});
5-动画监听
有start、repeat、end、cancel四个过程,可以监听。
//监听全部步骤
objectAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {
}
@Override
public void onAnimationEnd(Animator animator) {
}
@Override
public void onAnimationCancel(Animator animator) {
}
@Override
public void onAnimationRepeat(Animator animator) {
}
});
//选择性监听
objectAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
}
});
6-AnimationSet
可以和PropertyValuesHolder将动画融合,在此基础上还可以控制动画的顺序。
ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(imageView,"translationY", 300);
ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(imageView,"scaleX", 1f, 0, 1f);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(objectAnimator1, objectAnimator2);
animatorSet.setDuration(2000);
animatorSet.start();
7-在XML中使用属性动画
- 需要在res文件夹中创建
animator
文件夹!!
XML文件
在X轴上缩放,从1.0>0.5
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1000"
android:propertyName="scaleX"
android:valueFrom="1.0"
android:valueTo="0.5"
android:valueType="floatType">
</objectAnimator>
从XML中加载animator
Animator animator = AnimatorInflater.loadAnimator(this, R.animator.scalex);
animator.setTarget(imageView);
animator.start();
8-View直接使用animate()
是属性动画的一种简写形式。
imageView.animate() //获得animator
.alpha(0)
.y(300)
.setDuration(3000)
.withStartAction(new Runnable() {
@Override
public void run() {
}
})
.withEndAction(new Runnable() {
@Override
public void run() {
//结束动作后,在UI线程操作
runOnUiThread(new Runnable() {
@Override
public void run() {
}
});
}
})
.start(); //开始
3-布局动画
通过给ViewGroup设置布局动画,达到View逐渐呈现的过渡效果。
android:animateLayoutChanges="true"
者可以给布局添加系统默认的效果。
如果要自定义过渡效果,需要通过LayoutAnimationController
类来自定义,本质是给布局一个视图动画,在View出现时产生过渡效果。
LinearLayout mLinear = (LinearLayout) findViewById(R.id.mLinear);
//设置过渡动画
ScaleAnimation sa = new ScaleAnimation(0,1,0,1);
sa.setDuration(1000);
//设置布局动画的显示属性
//第一个参数,是需要作用的动画,而第二个参数,则是每个子View显示的delay时间
LayoutAnimationController lac = new LayoutAnimationController(sa,0.5f); lac.setOrder(LayoutAnimationController.ORDER_NORMAL);
//为ViewGroup设置布局动画
mLinear.setLayoutAnimation(lac);
当delay的时间不为0时,可以设置子View显示的顺序:
- LayoutAnimationController.ORDER_NORMAL——顺序
- LayoutAnimationController.ORDER_RANDOM——随机
- LayoutAnimationController.ORDER_REVERSE——反序
4-Interpolators(插值器)
插值器可以定义动画的变换速率。可以直接把插值器理解为动画变换的加速度。例如一个位移动画,如果使用线性插值器,那么在持续时间内,单位时间所移动的距离都是一样的;如果使用加速度插值器,那么单位时间内所移动的距离将越来越快。
Interpolator属性实际上是Animation类的一个XML属性,有很多系统值。
5-自定义动画
具体内容参考原著或者网上博客。
转载:复杂自定义动画实现
6-Android 5.x SVG矢量动画机制
1-SVG是什么?(Scalable Vetor Graphics)
- 可伸缩矢量图
- 定义用于网络的基于矢量的图形
- 使用XML格式定义图形
- 图像缩放不会影响质量
- 万维网联盟标准
- 与DOM和XSL之类的W3C标准是一个整体
2-SVG和Bitmap区别
- Bitmap是通过每个像素点上存储色彩信息来表示图像。
SCG是一个绘图标准。 - Bitmap放大不会失真。Bitmap需要为不同分辨率设计多套图表,SVG不需要。
3-SVG编辑器
SVG写法固定复杂,可以通过SVG编辑器完成。将图形编辑好后,可以使用编辑器转换为SVG代码。
4-Android中使用SVG
- VectorDrawable:创建基于XML的SVG图形
- AnimatedVectorDrawable:实现动画效果
1-VectorDrawable实例
在res
右击,选择最上面的New
,选择Vector Asset
。
使用系统默认矢量图或者阿里矢量图库下载的矢量图。
创建好后ic_cake_black_24dp.xml
如下:(我用系统默认图标)
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<group
android:name="test">
<path
android:fillColor="#FF000000"
android:pathData="M12,6c1.11,0 2,-0.9 2,-2 0,-0.38 -0.1,-0.73 -0.29,-1.03L12,0l-1.71,2.97c-0.19,0.3 -0.29,0.65 -0.29,1.03 0,1.1 0.9,2 2,2zM16.6,15.99l-1.07,-1.07 -1.08,1.07c-1.3,1.3 -3.58,1.31 -4.89,0l-1.07,-1.07 -1.09,1.07C6.75,16.64 5.88,17 4.96,17c-0.73,0 -1.4,-0.23 -1.96,-0.61L3,21c0,0.55 0.45,1 1,1h16c0.55,0 1,-0.45 1,-1v-4.61c-0.56,0.38 -1.23,0.61 -1.96,0.61 -0.92,0 -1.79,-0.36 -2.44,-1.01zM18,9h-5L13,7h-2v2L6,9c-1.66,0 -3,1.34 -3,3v1.54c0,1.08 0.88,1.96 1.96,1.96 0.52,0 1.02,-0.2 1.38,-0.57l2.14,-2.13 2.13,2.13c0.74,0.74 2.03,0.74 2.77,0l2.14,-2.13 2.13,2.13c0.37,0.37 0.86,0.57 1.38,0.57 1.08,0 1.96,-0.88 1.96,-1.96L20.99,12C21,10.34 19.66,9 18,9z"/>
</group>
</vector>
使用矢量图:
<ImageView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:src="@drawable/ic_cake_black_24dp"/>
2-AnimatedVectorDrawable实例:动画效果
创建animated-vector
标签的文件ic_cake_anim_vector
:
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/ic_cake_black_24dp">
<target
android:animation="@animator/scalex"
android:name="test">
</target>
</animated-vector>
- android:drawable需要使用矢量图
- android:animation中为objectAnimator的动画效果
- android:name为矢量图中(在上个实例里)
布局中引用:
<ImageView
android:id="@+id/svg_anim_imageview"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:src="@drawable/ic_cake_anim_vector"/>
开启动画:
ImageView imageView = (ImageView) findViewById(R.id.svg_anim_imageview);
((Animatable)imageView.getDrawable()).start();
- AnimatedVectorDrawable将静态的VectorDrawable和动态的ObjectAnimator连接起来。
5-SVG做简单动画
将一个横线从中间折断变成“X”的效果
1-绘制初始两条线
vector_two_line.xml
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="200dp"
android:height="200dp"
android:viewportWidth="100"
android:viewportHeight="100">
<group>
<path
android:name="path1"
android:pathData="M 20,80 L 50,80 80,80"
android:strokeColor="@color/colorAccent"
android:strokeWidth="3"
android:strokeLineCap="round"/>
<path
android:name="path2"
android:pathData="M 20,20 L 50,20 80,20"
android:strokeColor="@color/colorAccent"
android:strokeWidth="3"
android:strokeLineCap="round"/>
</group>
</vector>
2-动画效果(ObjectAnimator)
path1_animator:
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="200"
android:propertyName="pathData"
android:valueFrom="M 20,80 L 50,80 80,80"
android:valueTo="M 20,80 L 50,50 80,80"
android:valueType="pathType"
android:interpolator="@android:anim/bounce_interpolator">
</objectAnimator>
path2_animator:
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="200"
android:propertyName="pathData"
android:valueFrom="M 20,20 L 50,20 80,20"
android:valueTo="M 20,20 L 50,50 80,20"
android:valueType="pathType"
android:interpolator="@android:anim/bounce_interpolator">
</objectAnimator>
3-粘合静态矢量图和动态动画
vector_two_line_anim.xml
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/vector_two_line">
<target
android:animation="@animator/path1_animator"
android:name="path1">
</target>
<target
android:animation="@animator/path2_animator"
android:name="path2">
</target>
</animated-vector>
4-使用
<ImageView
android:id="@+id/two_line_imageview"
android:layout_width="50dp"
android:layout_height="50dp"
android:src="@drawable/vector_two_line_anim"/>
ImageView imageView = (ImageView) findViewById(R.id.two_line_imageview);
((Animatable)imageView.getDrawable()).start();
6-SVG:轨迹动画
轨迹动画,这里给上例的两条线在绘制的时候显示轨迹。
动画:
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1000"
android:propertyName="trimPathEnd"
android:valueFrom="0"
android:valueTo="1"
android:valueType="floatType"
android:interpolator="@android:interpolator/accelerate_decelerate">
</objectAnimator>
动画粘贴器:
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/vector_two_line">
<target
android:animation="@animator/trimpath_animator"
android:name="path1">
</target>
<target
android:animation="@animator/trimpath_animator"
android:name="path2">
</target>
</animated-vector>
ImageView:
<ImageView
android:id="@+id/trimpath_anim_imageview"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:src="@drawable/vector_trimpath_anim"/>
使用:
ImageView imageView = (ImageView) findViewById(R.id.trimpath_anim_imageview);
((Animatable)imageView.getDrawable()).start();
这里省略了一些书上的实例,可以自行查阅。大致关于Android动画机制的内容就这么多了,还需要以后深入学习!