属性动画学习笔记

传统动画:Drawable,Property,View
只能支持简单的缩放、平移、旋转、透明度基本的动画
无法做到带颜色的切换动画,3d旋转动画,停留在动画停止的位置。

引用参考来源:
Android 属性动画(Property Animation) 完全解析 (下)
Android 属性动画(Property Animation) 完全解析 (上)

Property Animation 属性动画

通过动画的方式改变对象的属性了

了解几个属性:

  • Duration 动画持续时间.默认300ms
  • Time interpolation 时间差,定义动画的变化率。如:LinearInterpolator、AccelerateDecelerateInterpolator
  • Repeat count and behavior:重复次数、以及重复模式;
  • Animator sets: 动画集合,定义一组动画

ObjectAnimator

提供了ofInt、ofFloat、ofObject,这几个方法都是设置动画作用的元素、作用的属性、动画开始、结束、以及中间的任意个属性值

使用实例:
360旋转效果:

1
2
3
4
ObjectAnimator//  
.ofFloat(view, "rotationX", 0.0F, 360.0F)//
.setDuration(500)//
.start();

注意:默认中心缩放,和中间对称线为反转线。当我们设置为左上角为中心点时,需要以下设置:

1
2
view.setPivotX(0);  
view.setPivotY(0);

若内部没有调用view的重绘,需要手动调用,添加AnimatorUpdateListener进行监听

1
2
3
4
5
6
7
anim.addUpdateListener(new AnimatorUpdateListener(){  
@Override
public void onAnimationUpdate(ValueAnimator animation){
view.postInvalidate();
view.invalidate();
}
});

扩展:通过使用addUpdateListener的思想,我们可以做更多的效果,而不局限与ObjectAnimator提供的几个动画效果的方法。

如:让View既可以缩小、又能够淡出(3个属性scaleX,scaleY,alpha):

1
2
3
4
5
6
7
8
9
10
11
anim.addUpdateListener(new AnimatorUpdateListener()  
{
@Override
public void onAnimationUpdate(ValueAnimator animation)
{

float cVal = (Float) animation.getAnimatedValue();
view.setAlpha(cVal);
view.setScaleX(cVal);
view.setScaleY(cVal);
}
});

另一种方式:使用propertyValuesHolder

1
2
3
4
5
6
7
8
9
public void propertyValuesHolder(View view)  {  
PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("alpha", 1f,
0f, 1f);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("scaleX", 1f,
0, 1f);
PropertyValuesHolder pvhZ = PropertyValuesHolder.ofFloat("scaleY", 1f,
0, 1f);
ObjectAnimator.ofPropertyValuesHolder(view, pvhX, pvhY,pvhZ).setDuration(1000).start();
}

ValueAnimator

主要用以移动的动画
提供的方法与ObjectAnimator相似:ofFloat
需要手动设置,进行addUpdateListener监听,否则无任何效果。这个跟ObjectAnimator很不同。

例子:
自由落体

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public void verticalRun( View view)  {  
ValueAnimator animator = ValueAnimator.ofFloat(0, mScreenHeight
- mBlueBall.getHeight());
animator.setTarget(mBlueBall);
animator.setDuration(1000).start();
// animator.setInterpolator(value)
animator.addUpdateListener(new AnimatorUpdateListener()
{
@Override
public void onAnimationUpdate(ValueAnimator animation)
{

mBlueBall.setTranslationY((Float) animation.getAnimatedValue());
}
});
}

抛物线(关键代码,需要重写:TypeEvaluator)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
valueAnimator.setEvaluator(new TypeEvaluator<PointF>()  {  
// fraction = t / duration
@Override
public PointF evaluate(float fraction, PointF startValue,
PointF endValue)

{

Log.e(TAG, fraction * 3 + "");
// x方向200px/s ,则y方向0.5 * 10 * t
PointF point = new PointF();
point.x = 200 * fraction * 3;
point.y = 0.5f * 200 * (fraction * 3) * (fraction * 3);
return point;
}
});
# 使用 进行更改x,y的坐标
@Override
public void onAnimationUpdate(ValueAnimator animation) {
PointF point = (PointF) animation.getAnimatedValue();
mBlueBall.setX(point.x);
mBlueBall.setY(point.y);
}

监听动画的开始、结束、被取消、重复等事件:

Animator.AnimatorListener,Animator.AnimatorPauseListener

AnimatorSet的使用

将动画进行组合,进行有顺序执行。

同时执行:

1
2
3
4
5
6
7
8
9
ObjectAnimator anim1 = ObjectAnimator.ofFloat(mBlueBall, "scaleX",  
1.0f, 2f);
ObjectAnimator anim2 = ObjectAnimator.ofFloat(mBlueBall, "scaleY",
1.0f, 2f);
AnimatorSet animSet = new AnimatorSet();
animSet.setDuration(2000);
animSet.setInterpolator(new LinearInterpolator());
//两个动画同时执行
animSet.playTogether(anim1, anim2);

顺序执行:(anim1,anim2,anim3同时执行 anim4接着执行 )

1
2
3
4
AnimatorSet animSet = new AnimatorSet();  
animSet.play(anim1).with(anim2);
animSet.play(anim2).with(anim3);
animSet.play(anim4).after(anim3);

使用xml文件来创建属性动画

xml布局

1
2
3
4
5
6
7
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"  
android:duration="1000"
android:propertyName="scaleX"
android:valueFrom="1.0"
android:valueTo="2.0"
android:valueType="floatType" >
</objectAnimator>

当然可以使用<set>代表AnimatorSet同样是将动画进行组合
对应的属性:

  • orderring 为together 同时执行(默认) sequentially 代表一个接一个

使用:

1
2
3
4
// 加载动画  
Animator anim = AnimatorInflater.loadAnimator(this, R.animator.scalex);
anim.setTarget(mMv);
anim.start();

Layout Animations 布局动画

当容器中的视图层次发生变化时存在过渡的动画效果。

1
2
3
4
5
6
7
LayoutTransition transition = new LayoutTransition();  
transition.setAnimator(LayoutTransition.CHANGE_APPEARING,
transition.getAnimator(LayoutTransition.CHANGE_APPEARING));
transition.setAnimator(LayoutTransition.APPEARING,
null);
...
mGridLayout.setLayoutTransition(transition); //作用在viewgroup上

过渡的类型一共有四种:

  • LayoutTransition.APPEARING 当一个View在ViewGroup中出现时,对此View设置的动画
  • LayoutTransition.CHANGE_APPEARING 当一个View在ViewGroup中出现时,对此View对其他View位置造成影响,对其他View设置的动画
  • LayoutTransition.DISAPPEARING 当一个View在ViewGroup中消失时,对此View设置的动画
  • LayoutTransition.CHANGE_DISAPPEARING 当一个View在ViewGroup中消失时,对此View对其他View位置造成影响,对其他View设置的动画
  • LayoutTransition.CHANGE 不是由于View出现或消失造成对其他View位置造成影响,然后对其他View设置的动画

注意:动画到底设置在谁身上,此View还是其他View

版本升级添加的方法

  • SDK11的时候,给View添加了animate方法
  • SDK12 添加 withStartAction
  • SDK16 添加 withEndAction
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// need API12  
mBlueBall.animate()//
.alpha(0)//
.y(mScreenHeight / 2).setDuration(1000)
// need API 12
.withStartAction(new Runnable() {
@Override
public void run() {
Log.e(TAG, "START");
}
// need API 16
}).withEndAction(new Runnable() {
@Override
public void run() {
Log.e(TAG, "END");
runOnUiThread(new Runnable() {
@Override
public void run() {
mBlueBall.setY(0);
mBlueBall.setAlpha(1.0f);
}
});
}
}).start();

学习资料:

[Android] 开发资料收集:动画
Android动画,一篇就够