属性动画算是Android动画里面比较麻烦的一种动画了。不过就是因为它麻烦所以也能更好地满足我们的需求。属性动画是在3.0以后添加的。功能十分强大。接下来我们将重点的讲讲。如果对其他几种动画不了解的话可以先看看我的前几篇博客初识android动画。下面的内容均在前几篇的基础上讲的。我们看一下官方提供的使用属性动画制作的酷炫的例子吧!!!
先给出官方的API 点击打开链接
属性动画与传统动画的区别
当我们点击按钮的时候,一个圆由位置一转到位置二。我们也为这个圆设置一个点击事件,当点击圆的时候弹出一个Toast。我们传统的做法是什么呢?肯定是设置一个传统的TranslateAnimation属性,为其设置位置就可以了。现在我们在位置一点击圆肯定能弹出一个Toast。但是我们的位置发生变化之后,我们再去点击圆发现没有Toast了。但是我们在原来的位置一上点击发现能够Toast,怎么回事呢?这就是传统动画的弊端了。 传统动画考虑的是一个View的重新绘制。当我们执行动画的时候其实就是一个个View不断地去重新绘制。而我们的属性动画就可以很好的解决这一问题。
属性动画一:ObjectAnimator
ObjectAnimator是属性动画里面比较简单但是也是会经常用到的一个对象。他其实执行的是一个异步任务。我们再给出官方的API 点击打开链接
那么我们如何去使用呢?接着前面提到的一个例子
我们定义了一个按钮,一张图片。点击按钮启动动画;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
//图片的点击事件
public void click(View view){
Toast.makeText(MainActivity.this, "点击了图片", Toast.LENGTH_SHORT).show();
}
//按钮的监听事件
public void move(View view){
ImageView imageView=(ImageView) findViewById(R.id.imageView1);
ObjectAnimator animator=new ObjectAnimator();
animator.ofFloat(imageView, "translationX", 0f,200f).start();
}
}
ObjectAnimator.ofFloat(imageView, "translationX", 0f,200f).setDuration(3000).start();
ObjectAnimator.ofFloat(imageView, "translationY", 0f,200f).setDuration(3000).start();
ObjectAnimator.ofFloat(imageView, "rotation", 0f,360f).setDuration(3000).start();
(2)同时使用
PropertyVlaueHolder:
PropertyValuesHolder p1=PropertyValuesHolder.ofFloat("translationX",0f,200f);
PropertyValuesHolder p2=PropertyValuesHolder.ofFloat("translationY", 0f,200f);
PropertyValuesHolder p3=PropertyValuesHolder.ofFloat("rotation", 0f,360f);
ObjectAnimator.ofPropertyValuesHolder(imageView, p1,p2,p3).setDuration(3000).start();
(3)使用AnimatorSet
ObjectAnimator animator1=ObjectAnimator.ofFloat(imageView, "translationX", 0f,200f).setDuration(3000);
ObjectAnimator animator2=ObjectAnimator.ofFloat(imageView, "translationY", 0f,200f).setDuration(3000);
ObjectAnimator animator3=ObjectAnimator.ofFloat(imageView, "rotation", 0f,360f).setDuration(3000);
AnimatorSet set=new AnimatorSet();
set.playTogether(animator1,animator2,animator3);
set.start();
我们使用以上的三种方法都可以实现同时播放我们的好几种动画。其中AnimatorSet功能最为强大。不仅仅可以同时播放好几种动画,还可以控制动画的播放顺序
//按照顺序依次播放
set.playSequentially(animator1,animator2,animator3);
//动画2和动画3同时播放,动画一在他们之后播放
set.play(animator2).with(animator3);
set.play(animator1).after(animator2);
属性动画二:监听事件
ObjectAnimator animator1=ObjectAnimator.ofFloat(imageView, "translationX", 0f,200f).setDuration(3000);
//添加监听事件
animator1.addListener(new AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationRepeat(Animator animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationEnd(Animator animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationCancel(Animator animation) {
// TODO Auto-generated method stub
}
});
//有选择的添加监听事件
animator1.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
// TODO Auto-generated method stub
super.onAnimationEnd(animation);
}
});
代码很简单一眼就能明白。
属性动画三: ValueAnimator数值发生器
public class MyActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.my_activity);
super.onCreate(savedInstanceState);
}
public void click(View view){
//获得Button对象
final Button button=(Button)findViewById(R.id.my_button);
//新建一个ValueAnimator,让其中的数值从0-10
ValueAnimator animator=ValueAnimator.ofInt(0,10);
//从0-10在10秒内变化
animator.setDuration(10000);
//为其添加事件
animator.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
//获得ValueAnimator的植
Integer value=(Integer) animation.getAnimatedValue();
button.setText(""+value);
}
});
animator.start();//启动动画
}
}
我们看到没有使用线程。也可以实现。现在大家应该能够自然而言的想到一些其他的一些应用场景了吧。例如在0-3之间我们产生一个时间,3-7之间做另外一件事等等。上面我们直接使用的ofInt。这是谷歌给我定义好的一种模式。那我们能不能自己定义一些数值计算器呢?答案是肯定的。
//自定义数值计算器
ValueAnimator animator=ValueAnimator.ofObject(new TypeEvaluator<PointF>() {
//通过evaluate返回各种各样的植,我们拿到这些值之后就可以为所欲为了。
@Override
public PointF evaluate(float arg0, PointF arg1, PointF arg2) {
// TODO Auto-generated method stub
return null;
}
});
fraction: :时间因子,从0-1之间变化 arg1 :开始值 arg2 :结束值
总结:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/imageView_h"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/h" />
<ImageView
android:id="@+id/imageView_g"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/g" />
<ImageView
android:id="@+id/imageView_f"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/f" />
<ImageView
android:id="@+id/imageView_e"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/e" />
<ImageView
android:id="@+id/imageView_d"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/d" />
<ImageView
android:id="@+id/imageView_c"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/c" />
<ImageView
android:id="@+id/imageView_b"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/b" />
<ImageView
android:id="@+id/imageView_a"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/a" />
</FrameLayout>
然后在我们activity中运用就可以了。
public class MainActivity1 extends Activity implements OnClickListener {
//定义一些图片资源
private int[] res = { R.id.imageView_a, R.id.imageView_b, R.id.imageView_c,
R.id.imageView_d, R.id.imageView_e, R.id.imageView_f, R.id.imageView_g, R.id.imageView_h };
//保存图片
private List<ImageView> imageViewList = new ArrayList<ImageView>();
//用于控制图片伸缩开关
private boolean flag=true;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//将图片添加进来
for (int i = 0; i < res.length; i++) {
ImageView imageView = (ImageView) findViewById(res[i]);
imageView.setOnClickListener(this);
imageViewList.add(imageView);
}
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.imageView_a:
if(flag){
startAnim();
}else{
stopAnim();
}
break;
}
}
//停止播放动画
@SuppressLint("NewApi")
private void stopAnim() {
for (int i = 0; i < res.length; i++) {
ObjectAnimator animator = ObjectAnimator.ofFloat(
imageViewList.get(i), "translationY", i * 100, 0f);
animator.setInterpolator(new BounceInterpolator()); //插值器
animator.setDuration(1000);
animator.setStartDelay(i * 500);
animator.start();
flag=true;
}
}
//开始播放动画
@SuppressLint("NewApi")
private void startAnim() {
for (int i = 1; i < res.length; i++) {
ObjectAnimator animator = ObjectAnimator.ofFloat(
imageViewList.get(i), "translationY", 0f, i * 100);
AnimatorSet mset=new AnimatorSet();
mset.playTogether(animator);
mset.setDuration(1000);
mset.setStartDelay(i*500);
mset.setInterpolator(new BounceInterpolator()); //插值器
mset.start();
flag=false;
}
}
}
如果看懂了源码之后你也可以自己修改制作各种不同的效果。