Android属性动画 (Property Animation)
昨天去学校的一个技术组织去面试,长这么大第一次面试紧张死了,到了那先去面试的JAVA当时太紧张,人家问我 JVM 的工作是什么我听成了Dalvik了自顾自的说了一大串(⊙﹏⊙)b……………….. ,然后去面试Android问到了一个我只听说过名字但是完全不知道名字的知识点—–属性动画,老心肝扑通扑通的啊 ~(>_<)~,回到宿舍赶紧撸了一下Android的属性动画~。
简介
大家都知道Android有两种动画一个叫补间动画 (平移,旋转,透明度,伸缩的变换)和帧动画,可能新手用的最多的就是补间动画(我就是……. ),那么属性动画是什么呢?他又有什么好处呢?
首先,补间动画并没有对View进行实质的改变只是让他看起来改变了,例如你写了一段代码利用补间动画把在屏幕左上角的Buttom移动到屏幕右下角,但是当你当你点击右下角的时候并没有触动点击事件,反而点击右上角View原来的位置会响应点击事件,所以View的实际的属性(例如X,Y坐标)没有改变他只是看起来改变了。。
你可以这样想,你在家拍了一张照然后PS了一下把背景换成了天安门,然后你发给你的朋友,你朋友一看会说“哇~你在天安门啊!”,其实你还是在家里O(∩_∩)O~。
而且属性动画不仅可以改变仅限的几种属性(平移,旋转,透明度,伸缩的变换),它还可以改变所有你可以手动set的属性。个人认为它就是一个计算器,计算出来把结果给我们然后我们把值赋给控件(也可以不是空间,你可以随意处理那些值)的属性。
下面我们就来看看如何使用属性动画。
ValueAnimator
这个类是属性动画最重要的类之一。先看看下面的代码:
demo1
final ImageView image = (ImageView) findViewById(R.id.image);
//设置起始值是0.0 终点值是500。
ValueAnimator anim = ValueAnimator.ofFloat(0.0f, 500.0f);
//动画执行3秒
anim.setDuration(3000);
//每当动画刷新一帧的时候就会调用这个方法,我们个已通过animation拿到当前时间点计算出来的值
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
//得到当前时间点计算得到的值
float x = (float) animation.getAnimatedValue();
设置给我们的ImageView
image.setX(x);
//改变View的横坐标重绘ImageView,有的View的方法会自动调用重绘,这里setx不调用所以我们自己调用invalidate
image.invalidate();
}
});
//动画开始
anim.start();
}
看一下效果
其实我们只是用ValueAnimator计算的值手动设置给了ImageView。
下面看一个补间动画没有的。
final ViewGroup viewGroup = (ViewGroup) findViewById(R.id.parent);
ValueAnimator anim = ValueAnimator.ofArgb(Color.BLACK, Color.RED);
anim.setRepeatCount(15);
anim.setDuration(10000);
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int x = (int) animation.getAnimatedValue();
viewGroup.setBackgroundColor(x);
}
});
anim.start();
}
看看这个,感觉属性动画厉害了吧!!
如果我们不光有int,float值还想使用我们自定义的类怎么办?ValueAnimation没有提供别的值的处理方法啊,这就要用到ofObject方法了。其实当前时间点的值是由Evaluator 来计算的,使用ofObject需要我们来自己定义一个Evaluator,下面我们看看如何自定义Evaluator .
ValueAnimator anim = ValueAnimator.ofObject(new TypeEvaluator<Point>() {
//自定义Evaluator来计算我们想要的结果
@Override
public Point evaluate(float fraction, Point startValue, Point endValue) {
//fraction :动画完成了百分之几,他的范围是0到1,1代表已经完成0代表未开始。
Point point = new Point();
point.x = (int) ((-1) * (startValue.x + fraction * (startValue.x - endValue.x)));
point.y = (int) ((-1) * (startValue.y + fraction * (startValue.y - endValue.y)));
return point;
}
}, new Point(0, 0), new Point(300, 300));
anim.setRepeatCount(5);
anim.setDuration(5000);
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
Point p = (Point) animation.getAnimatedValue();
image.setX(p.x);
image.setY(p.y);
image.invalidate();
}
});
anim.start();
这里就是实现了TypeEvaluato接口,然后实现他的evaluato方法,计算出来的结果返回之后可以通过onupdateListener得到。恩,这个也挺简单的哈。
ObjectAnimation
ObjectAnimation比ValueAnimation用起来更加简单,它继承了ValueAnimation,看看下面的小demo就会了:
//第一个参数是要改变的View,第二个是要改变的View的属性,后面两个不解释
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(image, "alpha", 1f, 0f);
objectAnimator.setDuration(3000);
objectAnimator.setRepeatCount(10);
objectAnimator.setRepeatMode(ObjectAnimator.REVERSE);
objectAnimator.start();
效果图:
这里需要注意的是要改变的行、属性,上面用的是alpha,这个属性不许有public的set方法(例如View里面有setAlpha函数)才可以使用 (有一种特殊情况需要这个属性同时也有get方法,感觉一般不会那样写大家去官网看一下吧)。怎么样这个是不是比ValueAnimation简单多了,但是它的灵活性大大降低了。
AnimatorSet
这个和AnimotionSet一样的作用,支持几种动画同时执行。
AnimatorSet set = new AnimatorSet();
ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(image, "alpha", 1f, 0f);
ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(image, "rotationX", 0f, 180f);
ObjectAnimator objectAnimator3 = ObjectAnimator.ofFloat(image, "rotationY", 180f, 0f);
set.setDuration(10000).play(objectAnimator1).with(objectAnimator2).after(objectAnimator3);
//先播放objectAnimator3 ,之后把objectAnimator2和objectAnimator1同时播放
set.start();
AnimotionSet也说完了,这个更简单。
监听器
ValueAnimotior和ObjectAnimatior都可以通过addListener方法添加监听器
ValueAnimatorAnimator anim = ObjectAnimator.ofFloat(view, "alpha", 1f, 0f);
//想要监听一部分状态的话可以new AnimatorListenerAdapter()然后复习要监听的方法
anim.addListener(new AnimatorListenerAdapter() {
public void onAnimationEnd(Animator animation) {
//处理
}
//监听全部状态
anim.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) {
}
});
XML实现动画
这个是最后要说的了和animotion差不多,先在res里面建立文件夹文件名字叫animator
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="3000"
android:valueType="floatType"
android:propertyName="alpha"
android:valueFrom="1.0"
android:valueTo="0.0"/>
然后在代码里:
ObjectAnimator objectAnimator = (ObjectAnimator) AnimatorInflater.loadAnimator(context, R.animator.test);
objectAnimator.start();
多个动画一起执行(来自官方文档)
<set android:ordering="sequentially">
<set>
<objectAnimator
android:propertyName="x"
android:duration="500"
android:valueTo="400"
android:valueType="intType"/>
<objectAnimator
android:propertyName="y"
android:duration="500"
android:valueTo="300"
android:valueType="intType"/>
</set>
<objectAnimator
android:propertyName="alpha"
android:duration="500"
android:valueTo="1f"/>
代码:
AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(myContext,
R.anim.property_animator);
set.setTarget(myObject);
set.start();
android:ordering=”sequentially是设置执行顺序是从上往下顺序执行,也可以设置成together这个是同时执行
可能还有一些偏僻的小细节没有记,到时候用到还是直接查文档吧!!。