学习本章将了解:
Android视图动画
Android属性动画
Android动画实例
7.1、Android View动画框架
Animation框架定义了透明度、旋转、缩放、位移几种常见的动画,而且控制的是整个View。
原理是:
1、每次绘制时View所在的ViewGroup中的drawChild函数获取该view的Animation的Transformation值
2、调用canvas.concat通过运算完成动画帧
3、如果动画没有完成就继续调用invalidate反复绘制。
7.1.1、视图动画:
优点:效率高,使用方便
缺点:只能做普通动画,避免交互动画
视图动画提供了:
AlphaAnimation:透明度动画
RotateAnimation:旋转动画
TranslateAnimation:位移动画
ScaleAnimation:缩放动画
7.1.2、动画集合AnimationSet,可以将动画以组合的形式展现出来
示例代码如下:
package com.imooc.viewanim;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.RotateAnimation;
import android.view.animation.ScaleAnimation;
import android.view.animation.TranslateAnimation;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void btnAlpha(View view) {
AlphaAnimation aa = new AlphaAnimation(0, 1);
aa.setDuration(1000);
view.startAnimation(aa);
}
public void btnRotate(View view) {
RotateAnimation ra = new RotateAnimation(0, 360, 100, 100);
ra.setDuration(1000);
view.startAnimation(ra);
}
public void btnRotateSelf(View view) {
RotateAnimation ra = new RotateAnimation(0, 360,
RotateAnimation.RELATIVE_TO_SELF, 0.5F,
RotateAnimation.RELATIVE_TO_SELF, 0.5F);
ra.setDuration(1000);
view.startAnimation(ra);
}
public void btnTranslate(View view) {
TranslateAnimation ta = new TranslateAnimation(0, 200, 0, 300);
ta.setDuration(1000);
view.startAnimation(ta);
}
public void btnScale(View view) {
ScaleAnimation sa = new ScaleAnimation(0, 2, 0, 2);
sa.setDuration(1000);
view.startAnimation(sa);
}
public void btnScaleSelf(View view) {
ScaleAnimation sa = new ScaleAnimation(0, 1, 0, 1,
Animation.RELATIVE_TO_SELF, 0.5F,
Animation.RELATIVE_TO_SELF, 0.5F);
sa.setDuration(1000);
view.startAnimation(sa);
}
public void btnSet(View view) {
AnimationSet as = new AnimationSet(true);
as.setDuration(1000);
AlphaAnimation aa = new AlphaAnimation(0, 1);
aa.setDuration(1000);
as.addAnimation(aa);
TranslateAnimation ta = new TranslateAnimation(0, 100, 0, 200);
ta.setDuration(1000);
as.addAnimation(ta);
view.startAnimation(as);
}
}
对于动画事件Andorid也提供了回调
代码如下:
ScaleAnimation sa;//任意一个动画类型
sa.setAnimationListener(new Animation.AnimationListener() {
//动画开发
@Override
public void onAnimationStart(Animation animation) {
}
//结束
@Override
public void onAnimationEnd(Animation animation) {
}
//重复
@Override
public void onAnimationRepeat(Animation animation) {
}
});
通过前面的实例,可以发现视图动画的效果比较局限,注定会被更丰富的动画所取代
7.2、Andorid属性动画分析
3.0之前已有Animation动画框架,但是有局限性,只能显示,不能响应事件
所以3.0之后,google就提出了属性动画
7.2.1、ObjectAnimator
以前的动画框架,不能改变事件的位置(按钮移动走了,点击事件还在移动前的位置)
而属性动画可以改变事件的位置
ObjectAnimator animator0 = ObjectAnimator.ofFloat(
mImageViews.get(0),
"alpha",
1F,
0.5F);
第一个参数:需要操控的view
第二个参数:需要操控的属性
最后一个参数:变化的值
注意:在使用ObjectAnimator的时候,操控的属性必须具有get,set方法,不然ObjectAnimator不起效
7.2.2、PropertyValuesHolder
类似视图动画中的AnimationSet,多种动画同时进行
7.2.3、ValueAnimator
它是属性动画的核心,ObjectAnimator继承自ValueAnimator
通常情况下我们在ValueAnimator中AnimatorUpdateListener监听数值的变换,完成动画的变换
7.2.4、动画的监听
一个完整的动画有:start、end、repeat、cancel的过程
1、监听所有事件:
代码如下:
ObjectAnimator animator0 = ObjectAnimator.ofFloat(mImageViews.get(0),
"alpha", 0.5F, 1F);
animator0.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
2、监听指定事件:
animator0.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
}
});
7.2.5、AnimatorSet
类似PropertyValuesHolder和视图动画中的AnimationSet,多种动画同时进行,同时也能控制播放顺序。
拓展:
android AnimatorSet AnimationSet 的区别
AnimatorSet 和 AnimationSet 都是动画集合。这里简单介绍下他们的异同,了解这些后在设计动画实现时才能得心应手。
AnimationSet 我们最常用的是调用其 addAnimation 将一个个不一样的动画组织到一起来,然后调用view 的 startAnimation 方法触发这些动画执行。功能较弱不能做到把集合中的动画按一定顺序进行组织然后在执行的定制。
AnimatorSet 我们最常用的是调用其play、before、with、after 等方法设置动画的执行顺序,然后调用其start 触发动画执行。
AnimationSet 与 AnimatorSet 最大的不同在于,AnimationSet 使用的是 Animation 子类、AnimatorSet 使用的是 Animator 的子类。
Animation 是针对视图外观的动画实现,动画被应用时外观改变但视图的触发点不会发生变化,还是在原来定义的位置。
Animator 是针对视图属性的动画实现,动画被应用时对象属性产生变化,最终导致视图外观变化。
7.2.6、在XML中使用属性动画
属性动画和视图动画一样,可以直接写在xml中
<objectAnimator
android:propertyName="alpha"android:duration="500"android:valueTo="1f"/>
Animator animator = AnimatorInflater.loadAnimator(getApplicationContext(), R.anim.an_test);
animator.setTarget("");
animator.start();
7.2.7、View的animate方法
Android 3.0之后,google给View增加了animate方法来直接驱动属性动画,是属性动画的一种简写方式
基本用法如下:
View v = null;
v.animate().alpha(0).setDuration(100).start();
7.3、Andorid布局动画
布局动画是作用在ViewGroup上,给ViewGroup增加View的时候,添加一个动画的过渡效果。
最简单的布局动画是在ViewGroup的XML中,添加下面的属性打开布局动画。
android:animateLayoutChanges="true"
也可以使用LayoutAnimationController来自定义一个过渡动画
7.4、插值器
interpolators:控制动画的速度
7.5、自定义动画
创建自定义动画非常简单,只需要实现它的applyTransformation的逻辑就可以了。通常情况下还需要覆盖父类的initialize方法实现初始化的一些工作。
7.6、Android 5.x SVG矢量动画机制
Google在Andorid5.x中增加了对矢量图形的支持
Google在Andorid5.x中提供了2个新的api来支持SVG
VectorDrawable——创建基于xml的SVG图形
AnimatedVectorDrawable——实现动画效果
具体用法可参考:
http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0825/3362.html
7.7、Android 动画特效
下面我们做个实例:
package com.imooc.anim;
import android.animation.Animator;
import android.animation.AnimatorInflater;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.animation.BounceInterpolator;
import android.widget.ImageView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
public class PropertyTest extends Activity implements View.OnClickListener {
private int[] mRes = {R.id.imageView_a, R.id.imageView_b, R.id.imageView_c,
R.id.imageView_d, R.id.imageView_e};
private List<ImageView> mImageViews = new ArrayList<ImageView>();
private boolean mFlag = true;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.property);
for (int i = 0; i < mRes.length; i++) {
ImageView imageView = (ImageView) findViewById(mRes[i]);
imageView.setOnClickListener(this);
mImageViews.add(imageView);
}
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.imageView_a:
if (mFlag) {
startAnim();
} else {
closeAnim();
}
break;
default:
Toast.makeText(PropertyTest.this, "" + v.getId(),
Toast.LENGTH_SHORT).show();
break;
}
}
private void closeAnim() {
ObjectAnimator animator0 = ObjectAnimator.ofFloat(mImageViews.get(0),
"alpha", 0.5F, 1F);
ObjectAnimator animator1 = ObjectAnimator.ofFloat(mImageViews.get(1),
"translationY", 200F, 0);
ObjectAnimator animator2 = ObjectAnimator.ofFloat(mImageViews.get(2),
"translationX", 200F, 0);
ObjectAnimator animator3 = ObjectAnimator.ofFloat(mImageViews.get(3),
"translationY", -200F, 0);
ObjectAnimator animator4 = ObjectAnimator.ofFloat(mImageViews.get(4),
"translationX", -200F, 0);
AnimatorSet set = new AnimatorSet();
set.setDuration(500);
set.setInterpolator(new BounceInterpolator());
set.playTogether(animator0, animator1, animator2, animator3, animator4);
set.start();
mFlag = true;
}
private void startAnim() {
ObjectAnimator animator0 = ObjectAnimator.ofFloat(
mImageViews.get(0),
"alpha",
1F,
0.5F);
ObjectAnimator animator1 = ObjectAnimator.ofFloat(
mImageViews.get(1),
"translationY",
200F);
ObjectAnimator animator2 = ObjectAnimator.ofFloat(
mImageViews.get(2),
"translationX",
200F);
ObjectAnimator animator3 = ObjectAnimator.ofFloat(
mImageViews.get(3),
"translationY",
-200F);
ObjectAnimator animator4 = ObjectAnimator.ofFloat(
mImageViews.get(4),
"translationX",
-200F);
AnimatorSet set = new AnimatorSet();
set.setDuration(500);
set.setInterpolator(new BounceInterpolator());
set.playTogether(
animator0,
animator1,
animator2,
animator3,
animator4);
set.start();
mFlag = false;
}
}
7.7.2、计时器动画
package com.imooc.anim;
import android.animation.ValueAnimator;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
public class TimerTest extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.timer);
View v = null;
v.animate().alpha(0).setDuration(100).start();
}
public void tvTimer(final View view) {
ValueAnimator valueAnimator = ValueAnimator.ofInt(0, 100);
valueAnimator.addUpdateListener(
new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
((TextView) view).setText("$ " +
(Integer) animation.getAnimatedValue());
}
});
valueAnimator.setDuration(3000);
valueAnimator.start();
}
}