浅析Android动画(二)——Property Anim属性动
属性动画从字面上看就是对于属性的变换,它与变换动画最大的区别就是属性动画注重与用户的交互
举个例子:在变换动画中,将一个imageView设置点击事件,将其从左往右移动100dp,点击现有位置的imageView,并不会有点击事件,点击原有的位置将触发点击事件;而属性变化中,imageView的真实位置跟随着动画的移动而移动
变换动画请走链接浅析Android动画(一)——Tween Anim
相似的,属性动画拥有和变换动画相同的一些动画,alpha,translate,rotate,scale……但却比变化动画又更加精细,归根结底它变换的是属性,所有View对象拥有的属性都可以被操作。
属性动画也可以在布局文件中声明和在代码中声明,但从我个人角度来看,更喜欢在代码使用的形式,在这里只贴代码,有兴趣的可以自己去研究一下xml中的使用。
基本使用:
ObjectAnimator.ofFloat(Object 0,String propertyName,float...values);
ObjectAnimator.ofInt(Object 0,String propertyName,int...values);
/**
- 第一个参数,要操作的对象
- 第二个参数,要操作的对象属性,对象拥有的get,set属性都可以操作,相同的属性有相同的起始点
- 第三个参数,float... values,变化的值,可以是一个,可以是多个 ,如果只有一个值,表示声明终止状态,并且无法多次触发动画效果,多个值可以多次触发效果
*/
共有方法:
setDuration(long duration);//设置时间
setStartDelay();//设置动画延迟播放的时间
setRepeatMode(int type);//设置重复模式,reverse反序,restart正序
setRepeatCount(int value);//设置重复次数,特殊的:-1为一直重复
addListener(AnimatorListener listener);//为动画设置监听事件,监听动画的开始、结束、取消、重复、暂停、恢复
setInterpolator(Interpolator interpolator);//设置插值器
Translate
属性:"translationX","translationY","X","Y",区别在于前二者是相对对象自身的左上角,后二者是相对于屏幕的左上角
//从现有位置移动到相对于 屏幕 左上角的位置,不可以重复,因为终点位置相同,多次触发不会重复效果,横坐标与原始位置一致
ObjectAnimator.ofFloat(mImageView,"Y",100f).setDuration(1000).start();```
//从相对于 屏幕 左上角的指定位置移动到相对于 屏幕 左上角的另一个位置,可以重复触发效果,因为有起点终点,横坐标与现有原始一致
ObjectAnimator.ofFloat(mImageView,"Y",0f,100f).setDuration(1000).start();```
//从相对于 自身 左上角的指定位置移动到相对于 自身 左上角的另一个位置,可以重复触发效果,因为有起点终点,横坐标与原始位置一致
ObjectAnimator.ofFloat(mImageView,"translationY",0f,100f).setDuration(1000).start();```
//从现有位置移动到相对于 自身 左上角的坐标,多次触发不会重复效果,横坐标与原始位置一致
ObjectAnimator.ofFloat(mImageView,"translationY",100f).setDuration(1000).start();```
类似的还有X方向的变化
Rotate
属性:"rotation","rotationX","rotationY"
"rotation"与变换动画中的一致,可以声明起止点,终点大的顺时针,否则逆时针,只声明一个终点,则旋转到相对于最原始的旋转角度
"rotationX"和"rotationY"是3维的动画效果:"rotationX"表示绕与X轴同方向的中线旋转(上下翻转),"rotationY"表示绕与Y轴同方向的中线旋转(左右翻转)
//旋转到相对于原始角度的值,不可以重复
ObjectAnimator.ofFloat(mImageView,"rotation",360f).setDuration(1000).start();```
//可以重复
ObjectAnimator.ofFloat(mImageView,"rotation",0f,180f).setDuration(1000).start();```
//绕x轴方向的中线旋转
ObjectAnimator.ofFloat(mImageView,"rotationX",0f,180f).setDuration(1000).start(); ```
//绕y轴方向的中线旋转
ObjectAnimator.ofFloat(mImageView,"rotationY",0f,360f).setDuration(1000).start();```
Scale
属性:"scaleX","scaleY"
ObjectAnimator.ofFloat(mImageView,"scaleX",0f).setDuration(1000).start();//不可多次触发
ObjectAnimator.ofFloat(mImageView,"scaleX",1f,0f).setDuration(1000).start();```
这个很好理解
#####Alpha
> 属性:"alpha"
`ObjectAnimator.ofFloat(mImageView,"alpha",0f).setDuration(1000).start();//不可多次触发`
`ObjectAnimator.ofFloat(mImageView,"alpha",1f,0f).setDuration(1000).start();`
这个也很好理解
###组合动画:
- 最简单的 :
这两个方法就已经可以进行同时进行组合动画了
ObjectAnimator.ofFloat(mImageView,"scaleX",0f).setDuration(1000).start();
ObjectAnimator.ofFloat(mImageView,"scaleY",0f).setDuration(1000).start();```
- 更好的办法:
系统提供了更好的办法:PropertyValuesHolder,字面上就可以看到它是属性值的保存容器
我们将动画先从PropertyValuesHolder使用:
PropertyValuesHolder p1=PropertyValuesHolder.ofFloat("scaleX",1f,0f);
PropertyValuesHolder p2=PropertyValuesHolder.ofFloat("scaleY",1f,0f);`
随后再调用
ObjectAnimator.ofPropertyValuesHolder(Object o,PropertyValuesHolder...values)方法
这个方法第一个参数是操作对象,第二个参数就是PropertyValuesHolder数组了;
`objectAnimator = ObjectAnimator.ofPropertyValuesHolder(mImageView, p1, p2);
objectAnimator.setDuration(1000);
objectAnimator.setRepeatMode(ValueAnimator.REVERSE);
objectAnimator.setRepeatCount(-1);
objectAnimator.start();```
- 更更更好的办法:
类似于变换动画的AnimationSet动画集合,属性动画有它专门的集合:AnimatorSet,并且可以更加丰富的操作动画
先创建3个Animator:
ObjectAnimator animator1 = ObjectAnimator.ofFloat(mImageView, "alpha", 1f, 0.2f);
ObjectAnimator animator2 = ObjectAnimator.ofFloat(mImageView, "rotationX", 0f, 360f);
ObjectAnimator animator3 = ObjectAnimator.ofFloat(mImageView, "rotationY", 0f, 360f);再创建AnimatorSetA:
AnimatorSet set=new AnimatorSet();```
接下来神奇的事情将会发生:
set.playTogether(animator1,animator2,animator3);//同时进行动画
set.playSequentially(animator2,animator1,animator3);//按顺序播放
set.play(animator1).with(animator2);//两个动画一起进行
set.play(animator3).after(1000);//延迟1秒
set.play(animator3).after(animator1);//3在前2个动画之后
set.play(animator3).before(animator1);//3在前2个动画之前
发现只要非常简单的代码就可以实现很丰富的动画操作
监听事件
animator和animatorSet都有此监听事件
set.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
Toast.makeText(AnimActivity.this,"anim end",Toast.LENGTH_SHORT).show();
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});```
这个AnimatorListener()是系统已经设置好的,但是有一点不好,四个方法都要实现,而且缺少了暂停和恢复的监听
幸好系统有另一个方法
set.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationCancel(Animator animation) {
super.onAnimationCancel(animation);
}
@Override
public void onAnimationEnd(Animator animation) {
Toast.makeText(AnimActivity.this,"anim end",Toast.LENGTH_SHORT).show();
}
@Override
public void onAnimationPause(Animator animation) {
Toast.makeText(AnimActivity.this,"anim pause",Toast.LENGTH_SHORT).show();
}
@Override
public void onAnimationResume(Animator animation) {
Log.d("jc","resume");
Toast.makeText(AnimActivity.this,"anim resume",Toast.LENGTH_SHORT).show();
}
});```
在这个匿名内部类里面可以选择性的重写这六个方法。
ValueAnimator:
ObjectAnimator也是继承了ValueAnimator这个类
属性动画的运行机制是通过不断地对值进行操作来实现的,而初始值和结束值之间的动画过渡就是由ValueAnimator这个类来负责计算的。
ValueAnimator mAnimator;
mAnimator=ValueAnimator.ofFloat(1,2);
//设置监听
mAnimator.setDuration(1000);mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float translate= (float) animation.getAnimatedValue();
Log.d("jc”,"translate"+translate);
}
});
//无限循环
mAnimator.setRepeatCount(-1);
mAnimator.setRepeatMode(ValueAnimator.REVERSE);
mAnimator.start();```
D/jc: translate1.0
D/jc: translate1.0007129
D/jc: translate1.0026846
D/jc: translate1.0061558
...
D/jc: translate1.9709702
D/jc: translate1.9792609
D/jc: translate1.986185
D/jc: translate1.9917226
D/jc: translate1.995858
D/jc: translate1.9984586
D/jc: translate1.9998422
D/jc: translate1.9998002
D/jc: translate1.998333
D/jc: translate1.9954448
D/jc: translate1.9914355
D/jc: translate1.9858159
D/jc: translate1.9788108
D/jc: translate1.9704404
...
D/jc: translate1.0328355
D/jc: translate1.0239887
D/jc: translate1.0169019
D/jc: translate1.0107095
D/jc: translate1.0059125
D/jc: translate1.0025245
D/jc: translate1.000555
D/jc: translate1.0000099```
可以看到结果在不断变换