动画分类:
逐帧动画(Frame)
补间动画(Tween)
属性动画(Property)(Android 3.0以后引入)
帧动画
定义:由N张静态图片收集起来,然后我们通过控制依次显示这些图片,形成动画。
实现帧动画,需要利用AnimationDrawable;
方法1. 编写Drawable,然后代码中调用start()以及stop()开始或停止播放动画;
方法2. 在Java代码中创建逐帧动画,创建AnimationDrawable对象,然后调用addFrame(Drawable frame,int duration)向动画中添加帧,接着调用start()和stop();
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false">
<item
android:drawable="@mipmap/img_miao1"
android:duration="80" />
<item
android:drawable="@mipmap/img_miao2"
android:duration="80" />
<item
android:drawable="@mipmap/img_miao3"
android:duration="80" />
...
</animation-list>
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Button btn_start;
private Button btn_stop;
private ImageView img_show;
private AnimationDrawable anim;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bindViews();
anim = (AnimationDrawable) img_show.getBackground();
}
private void bindViews() {
btn_start = (Button) findViewById(R.id.btn_start);
btn_stop = (Button) findViewById(R.id.btn_stop);
img_show = (ImageView) findViewById(R.id.img_show);
btn_start.setOnClickListener(this);
btn_stop.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_start:
anim.start();
break;
case R.id.btn_stop:
anim.stop();
break;
}
}
}
补间动画
定义:指定动画开始,以及动画结束“关键帧”,而动画变化的“中间帧”则由系统计算并补齐。
实现补间动画:在res目录下新建anim文件夹,右键new-Animation Resource file,新建文件的根目录都是set。
xml中,在其子节点中添加代码。
Andoird所支持的补间动画效果有如下这五种(第五种是前面几种的组合):
AlphaAnimation:透明度渐变效果,创建时许指定开始以及结束透明度,还有动画的持续时间,透明度的变化范围(0,1),0是完全透明,1是完全不透明;对应<alpha/>标签;
ScaleAnimation:缩放渐变效果,创建时需指定开始以及结束的缩放比,以及缩放参考点,还有动画的持续时间;对应<scale/>标签;
TranslateAnimation:位移渐变效果,创建时指定起始以及结束位置,并指定动画的持续时间即可;对应<translate/>标签;
RotateAnimation:旋转渐变效果,创建时指定动画起始以及结束的旋转角度,以及动画持续时间和旋转的轴心;对应<rotate/>标签;
AnimationSet:组合渐变,就是前面多种渐变的组合,对应<set/>标签。
1)AlphaAnimation(透明度渐变)
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:fromAlpha="1.0"
android:toAlpha="0.1"
android:duration="2000"/>
属性解释:
fromAlpha :起始透明度
toAlpha:结束透明度
透明度的范围为:0-1,完全透明-完全不透明
2)ScaleAnimation(缩放渐变)
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_interpolator"
android:fromXScale="0.2"
android:toXScale="1.5"
android:fromYScale="0.2"
android:toYScale="1.5"
android:pivotX="50%"
android:pivotY="50%"
android:fillAfter="false"
android:duration="2000"/>
属性解释:
fromXScale/fromYScale:沿着X轴/Y轴缩放的起始比例;
toXScale/toYScale:沿着X轴/Y轴缩放的结束比例;
以上四种属性值: 0.0表示收缩到没有,1.0表示正常无伸缩,值小于1.0表示收缩,值大于1.0表示放大;值为相应倍数pivotX/pivotY:缩放的中轴点X/Y坐标,即距离自身左边缘的位置,比如50%就是以图像的中心为中轴点;
以上两个属性值:从0%-100%中取值,50%为物件的X或Y方向坐标上的中点位置
3)TranslateAnimation(位移渐变)
anim_translate.xml:
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:fromXDelta="0"
android:toXDelta="320"
android:fromYDelta="0"
android:toYDelta="0"
android:duration="2000"/>
属性解释:
fromXDelta/fromYDelta:动画起始位置的X/Y坐标;
toXDelta/toYDelta:动画结束位置的X/Y坐标;
pivotX/pivotY:表示旋转动作的参考点,不设置表示默认以自己为参照物;
4)RotateAnimation(旋转渐变)
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:fromDegrees="0"
android:toDegrees="360"
android:duration="1000"
android:repeatCount="1"
android:repeatMode="reverse"/>
属性解释:
fromDegrees/toDegrees:旋转的起始/结束角度,当角度为负数表示逆时针旋转,当角度为正数表示顺时针旋转
repeatCount:旋转的次数,默认值为0,代表一次,假如是其他值,比如3,则旋转4次。另外,值为-1或者infinite时,表示动画永不停止
repeatMode:设置重复模式,默认restart,但只有当repeatCount大于0或者infinite或-1时才有效。还可以设置成reverse,表示偶数次显示动画时会做方向相反的运动!
5)AnimationSet(组合渐变)
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/decelerate_interpolator"
android:shareInterpolator="true" >
<scale
android:duration="2000"
android:fromXScale="0.2"
android:fromYScale="0.2"
android:pivotX="50%"
android:pivotY="50%"
android:toXScale="1.5"
android:toYScale="1.5" />
<rotate
android:duration="1000"
android:fromDegrees="0"
android:repeatCount="1"
android:repeatMode="reverse"
android:toDegrees="360" />
<translate
android:duration="2000"
android:fromXDelta="0"
android:fromYDelta="0"
android:toXDelta="320"
android:toYDelta="0" />
<alpha
android:duration="2000"
android:fromAlpha="1.0"
android:toAlpha="0.1" />
</set>
属性解释:
fillBefore/ fillAfter:true/false,表示动画的转化在动画结束后是否应用;
fillBefore是指动画结束时画面停留在第一帧,fillAfter是指动画结束是画面停留在最后一帧。
这2个参数不能在 alpha,scale,translate,rotate节点中设置,在其中设置不起作用;
必须1)在动画xml文件的set节点中设置,或者在Activity中设置setFillAfter()/setFillBefore()。pivot:这个属性主要是在translate 和 scale 动画中,这两种动画都牵扯到view 的“物理位置“发生变化,所以需要一个参考点。
pivotX和pivotY就共同决定了这个点;它的值可以是float或者是百分比数值。
pivotX取值如下,pivotY取值同理。参考点都50%、50%即View自己的中心点。
pivotX取值 | 含义 |
---|---|
10 | 参考点距离动画所在view自身左边缘10像素 |
10% | 参考点距离动画所在view自身左边缘 的距离是整个view宽度的10% |
10%p | 参考点距离动画所在view父控件左边缘的距离是整个view宽度的10% |
这5个标签有一个共有的属性android:interpolator,Interpolator用来控制动画的变化速度。
而Android中已经提供了五个可供选择的实现类:
- LinearInterpolator:动画以均匀的速度改变
- AccelerateInterpolator:在动画开始的地方改变速度较慢,然后开始加速
- AccelerateDeceerateInterpolator:在动画开始、结束的地方改变速度较慢,中间时加速
- CycleInterpolator:动画循环播放特定次数,变化速度按正弦曲线改变:Math.sin(2 * mCycles * Math.PI * input)
- DecelerateInterpolator:在动画开始的地方改变速度较快,然后开始减速
- AnticipateInterpolator:反向,先向相反方向改变一段再加速播放
- AnticipateOvershootInterpolator:开始的时候向后然后向前甩一定值后返回最后的值
- BounceInterpolator: 跳跃,快到目的值时值会跳跃,如目的值100,后面的值可能依次为85,77,70,80,90,100
- OvershottInterpolator:回弹,最后超出目的值然后缓慢改变到目的值
6)实例
activity_main.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/btn_alpha"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="透明度渐变" />
<Button
android:id="@+id/btn_scale"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="缩放渐变" />
<Button
android:id="@+id/btn_tran"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="位移渐变" />
<Button
android:id="@+id/btn_rotate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="旋转渐变" />
<Button
android:id="@+id/btn_set"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="组合渐变" />
<ImageView
android:id="@+id/img_show"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="48dp"
android:src="@mipmap/img_face" />
</LinearLayout>
MainActivity.Java:
调用AnimationUtils.loadAnimation()加载动画,View控件调用startAnimation开启动画。
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private Button btn_alpha;
private Button btn_scale;
private Button btn_tran;
private Button btn_rotate;
private Button btn_set;
private ImageView img_show;
private Animation animation = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bindViews();
}
private void bindViews() {
btn_alpha = (Button) findViewById(R.id.btn_alpha);
btn_scale = (Button) findViewById(R.id.btn_scale);
btn_tran = (Button) findViewById(R.id.btn_tran);
btn_rotate = (Button) findViewById(R.id.btn_rotate);
btn_set = (Button) findViewById(R.id.btn_set);
img_show = (ImageView) findViewById(R.id.img_show);
btn_alpha.setOnClickListener(this);
btn_scale.setOnClickListener(this);
btn_tran.setOnClickListener(this);
btn_rotate.setOnClickListener(this);
btn_set.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btn_alpha:
animation = AnimationUtils.loadAnimation(this,
R.anim.anim_alpha);
img_show.startAnimation(animation);
break;
case R.id.btn_scale:
animation = AnimationUtils.loadAnimation(this,
R.anim.anim_scale);
img_show.startAnimation(animation);
break;
case R.id.btn_tran:
animation = AnimationUtils.loadAnimation(this,
R.anim.anim_translate);
img_show.startAnimation(animation);
break;
case R.id.btn_rotate:
animation = AnimationUtils.loadAnimation(this,
R.anim.anim_rotate);
img_show.startAnimation(animation);
break;
case R.id.btn_set:
animation = AnimationUtils.loadAnimation(this,
R.anim.anim_set);
img_show.startAnimation(animation);
break;
}
}
}
动画状态的监听
调用动画对象的: setAnimationListener(new AnimationListener())方法,重写下面的三个方法:
onAnimationStart():动画开始;
onAnimtaionRepeat():动画重复;
onAnimationEnd():动画结束;
为View动态设置动画效果
静态加载:先调用AnimationUtils.loadAnimation(),然后View控件用startAnimation()开始动画;
动态加载:即直接创建一个动画对象,用Java代码完成设置,再调用startAnimation开启动画。
属性动画
定义:通过不断地对属性值进行操作的机制,并将值赋值到指定对象的指定属性上,从而实现动画效果。
使用属性动画原因:
- 补间动画只是改变了View的显示效果而已,而不会真正去改变View的属性,即只是单纯的动画效果;
- 视觉上,补间动画的set节点中设置android:fillAfter="true",可以实现动画结束后保留在最后一帧,即应用动画效果的改变;
- 实际上,补间动画只是将view绘制到指定位置,形成动画,实际上的控件依然停留在原有位置;
- 补间动画只能够实现移动、缩放、旋转和淡入淡出这四种动画操作,即无扩展性,无法实现其他效果;
- 补间动画是只能够作用在View上的动画,对于自定义View无法添加补间动画。
1)ValueAnimator
ValueAnimator负责进行对不断变化的属性值的计算,以实现初始值和结束值之间的动画过渡。
将初始值和结束值提供给ValueAnimator,并且告诉它动画所需运行的时长,ValueAnimator就会自动完成从初始值平滑地过渡到结束值这样的效果。除此之外,ValueAnimator还负责管理动画的播放次数、播放模式、以及对动画设置监听器等。
使用流程:
- 调用ValueAnimator的ofInt(),ofFloat()或ofObject()静态方法创建ValueAnimator实例;方法参数为多个对应类型的值。
- 调用实例的setXxx方法设置动画持续时间,插值方式,重复次数等;
- 调用实例的addUpdateListener添加AnimatorUpdateListener监听器,在该监听器中可以获得ValueAnimator计算出来的值,值应用到指定对象上;
- 调用实例的start()方法开启动画。
使用范例:
//旋转的同时透明度变化
private void raAnimator(){
ValueAnimator rValue = ValueAnimator.ofInt(0, 360);
rValue.setDuration(1000L);
rValue.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int rotateValue = (Integer) animation.getAnimatedValue();
img_babi.setRotation(rotateValue);
float fractionValue = animation.getAnimatedFraction();
img_babi.setAlpha(fractionValue);
}
});
rValue.setInterpolator(new DecelerateInterpolator());
rValue.start();
}
2)ObjectAnimator
ObjectAnimator为ValueAnimator的子类,使用方法类似于ValueAnimator。
ObjectAnimator能对任意对象的任意属性进行动画操作的,使用范围更广。
ObjectAnimator使用更为简单,不需要自己写回调。
ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "alpha", 1f, 0f, 1f);
//ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "rotation", 0f, 360f);
//ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "translationX", curTranslationX, -500f, curTranslationX);
//ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "scaleY", 1f, 3f, 1f);
animator.setDuration(5000);
animator.start();
对于ObjectAnimator.ofFloat()方法,第二个参数即对应的ObjectAnimator指定要改变的对象的值,可以为任意的值。
常用的参数项有:alpha、rotation、translationX和scaleY等等。
ObjectAnimator内部的工作机制并不是直接对传入的属性名进行操作的,而是会去寻找这个属性名对应的get和set方法,因此alpha属性所对应的get和set方法应该就是getAlpha()与setAlpha(),这两个方法由View对象提供,同理,其他属性一样。即只要继承自View的类都可以对其进行这些动画操作。
3)AnimatorSet
实现组合动画功能
实现组合动画功能主要需要借助AnimatorSet这个类,这个类提供了一个play()方法,如果我们向这个方法中传入一个Animator对象(ValueAnimator或ObjectAnimator)将会返回一个AnimatorSet.Builder的实例。
AnimatorSet.Builder中包括以下四个方法:
- after(Animator anim) 将现有动画插入到传入的动画之后执行
- after(long delay) 将现有动画延迟指定毫秒后执行
- before(Animator anim) 将现有动画插入到传入的动画之前执行
- with(Animator anim) 将现有动画和传入的动画同时执行
ObjectAnimator rotate = ObjectAnimator.ofFloat(textview, "rotation", 0f, 360f);
ObjectAnimator fadeInOut = ObjectAnimator.ofFloat(textview, "alpha", 1f, 0f, 1f);
ObjectAnimator moveIn = ObjectAnimator.ofFloat(textview, "translationX", -500f, 0f);
AnimatorSet animSet = new AnimatorSet();
animSet.play(rotate).with(fadeInOut).after(moveIn);
animSet.setDuration(5000);
animSet.start();
4)AnimatorListener
Animator类中提供了addListener()方法,这个方法接收一个AnimatorListener。
实现AnimatorListener监听动画的各种事件。
AnimatorListener中重写下面全部的四个回调方法:
anim.addListener(new AnimatorListener() {
// 动画开始
public void onAnimationStart(Animator animation) {
}
// 动画重复执行
public void onAnimationRepeat(Animator animation) {
}
// 动画结束
public void onAnimationEnd(Animator animation) {
}
// 动画取消
public void onAnimationCancel(Animator animation) {
}
});
当只想重写其中部分方法时,接收的是AnimatorListenerAdapter,解决接口繁琐的问题。
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
}
});
5)使用xml定义动画
使用标签定义动画,Activity中调用AnimatorInflater的loadAnimator来将XML动画文件加载进来,然后再调用setTarget()方法将这个动画设置到某一个对象上面,最后再调用start()方法启动动画。
但是xml定义动画效果容易失效!建议使用Java代码方式动态加载动画
在res目录下新建animator文件夹,右键new-Animation Resource file,新建文件的根目录都是setXML中,在其子节点中添加代码。
- animator :对应代码中的ValueAnimator
- objectAnimator :对应代码中的ObjectAnimator
- set :对应代码中的AnimatorSet
定义动画
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:ordering="together">
<objectAnimator
android:propertyName="string"
android:duration="1000"
android:valueFrom="@android:color/white"
android:valueTo="@android:color/holo_green_dark"
android:startOffset="500"
android:repeatCount="1"
android:repeatMode="restart"
android:valueType="intType"/>
<animator
android:duration="1000"
android:valueFrom="@android:color/white"
android:valueTo="@android:color/holo_green_dark"
android:startOffset="10"
android:repeatCount="1"
android:repeatMode="restart"
android:valueType="intType"/>
</set>
使用动画
Animator animator = AnimatorInflater.loadAnimator(context, R.animator.anim_file);
animator.setTarget(view);
animator.start();
ValueAnimator、ObjectAnimator高级用法:
http://blog.csdn.net/guolin_blog/article/details/43816093
http://blog.csdn.net/guolin_blog/article/details/44171115