属性动画,就是通过控制对象中的属性值产生的动画。属性动画是目前最高级的2D动画系统。

在API Level 11中添加。Property Animation号称能控制一切对象的动画,包括可见的和不可见的。

但是,日常开发中我们一般都是对UI定制动画。

使用ObjectAnimator

ObjectAnimator是其中比较容易使用的一个动画类,它继承自ValueAnimator,

说比较容易使用是因为它在动画启动后自动监视属性值的变化并把值赋给对象属性,

而ValueAnimator则只监视属性值的变化,但不会自动在属性中应用该值,因此我们需要手动应用这些值。

代码:

//创建一个水平移动的动画对象,从位置0到300平移
final ObjectAnimator translation = ObjectAnimator.ofFloat(tv, "translationX", 0f, 300f);
translation.setDuration(1500);

只需两行就可以创建一个简单可运行的移动动画。

当然还有其他setxxx()方法可以控制动画的高级行为。

例如:添加一个插值器等

translation.setInterpolator(new AccelerateDecelerateInterpolator());

运行效果:

使用ValueAnimator

ValueAnimtor动画的创建基本上和ObjectAnimator一样,只是我们需要手动应用属性值

代码:

final ValueAnimator translation = ValueAnimator.ofFloat(0f, 300f);
translation.setDuration(1500);

有点不一样的是在创建对象的时候,ValueAnimator无需指定属性名称

只需指定动画的执行范围。

上面我们已经说了,ValueAniamtor不会自动应用属性值,因此我们需要添加一个动画监听器

translation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
{
@Override
public void onAnimationUpdate(ValueAnimator animation)
{
tv.setTranslationX((float) animation.getAnimatedValue());
}
});

tv是我们需要执行动画的对象,这里是一个TextView对象。

要使tv对象的动画执行,我们就要在监听器中使用对应setxxx方法更新tv的属性值,

而这些值我们可以使用animation对象的getAnimatedValue方法获得。

使用动画监听器执行不同的任务

通过监听器我们可以在动画的不同状态执行不同的任务

translation.addListener(new Animator.AnimatorListener()
{
@Override
public void onAnimationStart(Animator animation)
{ } @Override
public void onAnimationCancel(Animator animation)
{ } @Override
public void onAnimationRepeat(Animator animation)
{ } @Override
public void onAnimationEnd(Animator animation)
{ }
});

例如:我们可以在前一个动画执行完毕之后执行另一个动画

translation.addListener(new Animator.AnimatorListener()
{
@Override
public void onAnimationStart(Animator animation)
{ } @Override
public void onAnimationCancel(Animator animation)
{ } @Override
public void onAnimationRepeat(Animator animation)
{ } @Override
public void onAnimationEnd(Animator animation)
{
ObjectAnimator rotation = ObjectAnimator.ofFloat(tv, "rotation", 0f, 360f);
rotation.setDuration(1500);
rotation.start();
}
});

执行效果:

使用PropertyValuesHolder控制多个对象属性

例如我们对某个对象进行缩放控制的时候,就需要同时改变对象的x轴和y轴的值

这个时候我们就可以使用ObjectAnimator的ofPropertyValuesHolder()方法配合PropertyValuesHolder对象

//把按钮放大1.5倍
PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("scaleX", 1f, 1.5f);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("scaleY", 1f, 1.5f);
final ObjectAnimator scale = ObjectAnimator.ofPropertyValuesHolder(btnStart, pvhX, pvhY); final ValueAnimator translation = ValueAnimator.ofFloat(0f, 300f);
translation.setDuration(1500);
btnStart.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v)
{
//执行放大动画
scale.start();
translation.start();
}
});

运行效果:

使用Keyframe对象控制多属性动画

Keyframe对象对多属性动画的控制更加灵活,因为我们可以更好地控制每个时间段执行的动画距离

        Keyframe keyframe0 = Keyframe.ofFloat(0f, 0);
Keyframe keyframe1 = keyframe.ofFloat(.3f, 100);
Keyframe keyframe2 = keyframe.ofFloat(.4f, 200);
Keyframe keyframe3 = keyframe.ofFloat(1f, 200);
        PropertyValuesHolder pvhM = PropertyValuesHolder.ofKeyframe("translationX", keyframe0,keyframe1, keyframe2,keyframe3);
final ObjectAnimator trans = ObjectAnimator.ofPropertyValuesHolder(tv, pvhM);
trans.setDuration(1500);
final ValueAnimator translation = ValueAnimator.ofFloat(0f, 300f);
translation.setDuration(1500);
btnStart.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v)
{
//执行放大动画
scale.start();
trans.start();
//translation.start();
}
});

代码分析:

每个keyframe变量第一个参数执行总时间0%~100%,0表示动画未执行,1代码动画执行完毕

keyframe0代表动画在0%时的位置

keyframe1代表动画在30%时所处的位置

keyframe2代表动画在最后一个时间段所处的位置

keyframe3代表在200个单位距离时动画完成已经停止,加上这一行是为了动画停止后对象不会消失

运行效果:

上面的图片虽然不是看得很清楚,但是可以看见在最后一段时间动画突然加快。

原因是我们在定义最后一个keyframe的时候是用10%的时间走100个单位距离,

即它要在最短的时间走最多的距离,所以它必须加快速度才能完成这个任务。

不加keyframe3时的运行效果:

完整代码:

package com.whathecode.propertyanimation;

import android.animation.Animator;
import android.animation.Keyframe;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView; public class MainActivity extends ActionBarActivity
{ @Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); final TextView tv = (TextView) findViewById(R.id.tv); Button btnStart = (Button) findViewById(R.id.start);
/* //创建一个水平移动的动画对象,从位置0到300平移
final ObjectAnimator translation = ObjectAnimator.ofFloat(tv, "translationX", 0f, 300f);
translation.setDuration(1500);
*/ //把按钮放大1.5倍
PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("scaleX", 1f, 1.5f);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("scaleY", 1f, 1.5f);
final ObjectAnimator scale = ObjectAnimator.ofPropertyValuesHolder(btnStart, pvhX, pvhY); Keyframe keyframe0 = Keyframe.ofFloat(0f, 0);
        Keyframe keyframe1 = keyframe.ofFloat(.3f, 100);
Keyframe keyframe2 = keyframe.ofFloat(.4f, 200);
Keyframe keyframe3 = keyframe.ofFloat(1f, 200);
PropertyValuesHolder pvhM = PropertyValuesHolder.ofKeyframe("translationX", keyframe0,keyframe1, keyframe2,keyframe3);
final ObjectAnimator trans = ObjectAnimator.ofPropertyValuesHolder(tv, pvhM);
trans.setDuration(1500);
final ValueAnimator translation = ValueAnimator.ofFloat(0f, 300f);
translation.setDuration(1500);
btnStart.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v)
{
//执行放大动画
scale.start();
trans.start();
//translation.start();
}
}); translation.addListener(new Animator.AnimatorListener()
{
@Override
public void onAnimationStart(Animator animation)
{ } @Override
public void onAnimationCancel(Animator animation)
{ } @Override
public void onAnimationRepeat(Animator animation)
{ } @Override
public void onAnimationEnd(Animator animation)
{
ObjectAnimator rotation = ObjectAnimator.ofFloat(tv, "rotation", 0f, 360f);
rotation.setDuration(1500);
rotation.start();
}
}); translation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
{
@Override
public void onAnimationUpdate(ValueAnimator animation)
{
tv.setTranslationX((float) animation.getAnimatedValue());
}
});
}
}

最新文章

  1. 使用Java实现单线程模式
  2. 安装 Ubuntu 后的个人常用配置
  3. 使用PL/SQL编写存储过程访问数据库
  4. 解决ADT升级报错
  5. 教程-经典Delphi教程网
  6. 内存管理概述、内存分配与释放、地址映射机制(mm_struct, vm_area_struct)、malloc/free 的实现
  7. 如何解决eclipse上的Android程序“Please ensure that adb is correctly located at 'D:\eclipse\sdk\platform-tools\adb.exe' and can be executed.”小问题?
  8. [java]SpringMVC+Swagger实现自动接口
  9. winform实现矩形框截图
  10. Nginx负载均衡策略
  11. js关联数组
  12. node.js同步读取与异步读取文件
  13. 如何在IIS上发布网站 在阿里云服务器windows server2012r iis上部署.net网站
  14. C/C++ strict-aliasing
  15. 剑指Offer 31. 整数中1出现的次数(从1到n整数中1出现的次数) (其他)
  16. 迭代器模块 itertools
  17. 【BZOJ】 Hash Killer I II III
  18. SqlServer 循环建表、删除表、更新表
  19. Mybatis-generator插件,用于自动生成Mapper和POJO
  20. vue教程2-08 自定义键盘信息、监听数据变化vm.$watch

热门文章

  1. 从SVN一键对比版本
  2. 【MySQL案例】error.log的Warning:If a crash happens thisconfiguration does not guarantee that the relay lo(转)
  3. undo文件丢失或损坏
  4. 【css预处理器】------sass的基本语法------【巷子】
  5. 焦作网络赛L-Poor God Water【矩阵快速幂】
  6. 实现VMware下CentOS和Windows之间的复制粘贴
  7. com.mysql.jdbc.Driver to com.mysql.cj.jdbc.Driver
  8. 程序入口函数和glibc及C++全局构造和析构
  9. SQLAlchemy中scoped_session实现线程安全
  10. IIS7.5站点配置