Android 系统的坐标系,屏幕左上角为坐标原点,假如屏幕为1080*1980,那么左上角为(0,0),右上角为(1080,0),左下角为(0,1980),右下角为(1080,1980)
此动画也被称作补间动画,视图动画。可以在一个视图容器内执行一系列简单变换(位置、大小、旋转、透明度)。如果有一个ImageView对象,可以实现移动、旋转、缩放、透明度设置其文本。
Tween Animation只能应用于View对象,而且只支持一部分属性,如支持缩放旋转而不支持背景颜色的改变。
而且对于View animation,它只是改变了View对象绘制的位置,而没有改变View对象本身。
可以给一个View同时设置多个动画,比如从透明至不透明的淡入效果,与从小到大的放大效果,这些动画可以同时进行,也可以在一个完成之后开始另一个。
公共属性:
属性 | 描述 |
Duration | 动画持续时间(毫秒) |
fillAfter | 设置为true,动画转化在动画结束后被应用 |
fillBefore | 设置为true,动画转化在动画开始前被应用 |
interpolator | 动画插入器(加速,减速) |
repeatCount | 动画重复次数 |
repateMode | 顺序/倒序重复 |
startOffset | 动画之间的时间间隔 |
java | xml | 描述 |
---|---|---|
AlphaAnimation | 放置在res/anim/目录下 |
渐变透明度动画效果 |
RotateAnimation | 放置在res/anim/目录下 |
画面转移旋转动画效果 |
ScaleAnimation | 放置在res/anim/目录下 |
渐变尺寸伸缩动画效果 |
TranslateAnimation | 放置在res/anim/目录下 |
画面转换位置移动动画效果 |
AnimationSet | 放置在res/anim/目录下 |
一个持有其它动画元素alpha、scale、translate、rotate或者其它set元素的容器 |
(java代码实现比xml实现更灵活)
实现方法:xml布局形式:指定一个布局文件:res->anim->alpha
然后在java代码中调用工具类,并实现给view对象添加动画:
case R.id.btn_Alpha:
// 利用AnimationUtils工具类,指定alphaXML文件,添加一个动画
loadAnimation = AnimationUtils.loadAnimation(MainActivity.this, R.anim.alpha);
// 为imageView添加动画
imageView.startAnimation(loadAnimation);
break;
实现方法与Alpha类似,不再累赘:
case R.id.btn_Scale:
loadAnimation = AnimationUtils.loadAnimation(MainActivity.this, R.anim.scale);
imageView.startAnimation(loadAnimation);
break;
实现方法与Alpha类似,不再累赘:
case R.id.btn_Translate:
loadAnimation = AnimationUtils.loadAnimation(MainActivity.this,R.anim.translate);
imageView.startAnimation(loadAnimation);
break;
实现方法与Alpha类似,不再累赘:
case R.id.btn_Rotate:
loadAnimation = AnimationUtils.loadAnimation(MainActivity.this,R.anim.rotate);
imageView.startAnimation(loadAnimation);
break;
case R.id.btn_zuhe:
/*
* 方法1:通过为当前loadAnimation实现监听器,重写方法后,在onAnimationEnd(Animation animation)方法中执行定义的第二个动画
* */
loadAnimation = AnimationUtils.loadAnimation(MainActivity.this, R.anim.alpha);
imageView.startAnimation(loadAnimation);
final Animation loadAnimation2 = AnimationUtils.loadAnimation(MainActivity.this, R.anim.rotate);
loadAnimation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
imageView.startAnimation(loadAnimation2);
}
@Override
public void onAnimationRepeat(Animation animation) {
}
case R.id.btn_zuhe2:
/*
* 方法二:设定一个动画集:
* 写一个动画集,AnimationSet,在其中定义动画A和B,为动画B设置startOffset,其值就是前一个动画播放所需的时间
* */
loadAnimation = AnimationUtils.loadAnimation(MainActivity.this, R.anim.continue_btn2);
imageView.startAnimation(loadAnimation);
break;
case R.id.btn_change:
/*
* 此实例显示Activity之间跳转时的动画
* overridePendingTransition()方法,第一个参数传入进入新活动的动画,第二个参数传递推出此活动时的动画
* */
Intent intent = new Intent(MainActivity.this, Main2Activity.class);
startActivity(intent);
overridePendingTransition(R.anim.rotate, R.anim.alpha);
break;
使用animation-list标签来分组一个item标签集合,定义要显示的图片,指定显示它的时间(毫秒)
在java代码中调用:
case R.id.btn_Frame:
// 设置动画XML资源
imageView.setImageResource(R.drawable.anim_list);
// 获取动画对象
AnimationDrawable animationDrawable = (AnimationDrawable) imageView.getDrawable();
// 启动动画
// 停止动画可用.stop()方法
animationDrawable.start();
break;
所谓的布局动画是指作用的ViewGroup上,给ViewGroup增加子View时添加一个动画过度效果。使用LayoutAnimationController。
下面是加载一个具有ListView的Activity,显示相应的动画效果
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main3);
initView();
list = new ArrayList();
addListitem();
// ArrayAdapter<>第一个参数传入上下文对象,第二个参数传入listview子项布局,第三项传入list对象(资源)
ArrayAdapter adapter = new ArrayAdapter(this,R.layout.listitem, list);
listView.setAdapter(adapter);
// 通过layoutAnimationController添加动画
LayoutAnimationController layoutAnimationController = new LayoutAnimationController(AnimationUtils.loadAnimation(Main3Activity.this, R.anim.list_in));
// 指定子项动画加载的顺序
layoutAnimationController.setOrder(LayoutAnimationController.ORDER_RANDOM);
// 将此动画附在listview上
listView.setLayoutAnimation(layoutAnimationController);
listView.startLayoutAnimation();
}
private void addListitem() {
for (int i = 0; i < 50; i++){
list.add("liebiaoxiang:" + i);
}
}
private void initView() {
listView = findViewById(R.id.listview);
}
属性动画系统是一个强大的框架,允许动画几乎任何东西。可以定义动画以随时间更改任何对象属性,无论它是否绘制到屏幕上。属性动画在指定的时间长度内更改属性(对象中的字段)值。要为某些内容设置动画,请指定要设置动画的对象属性,例如对象在屏幕上的位置,要为其设置动画的时间长度以及要在其间设置动画的值。
属性动画系统允许定义动画的以下特征:
类 | 描述 |
ValueAnimator |
属性动画的主要计时引擎,它还计算要设置动画的属性的值。它具有计算动画值的所有核心功能,包含每个动画的计时详细信息,有关动画是否重复的信息,接收更新事件的侦听器以及设置要评估的自定义类型的功能。动画属性有两个部分:计算动画值并在正在设置动画的对象和属性上设置这些值。ValueAnimator 不会执行第二部分,因此您必须侦听由计算的值的更新,ValueAnimator 并使用您自己的逻辑修改要设置动画的对象。 |
ObjectAnimator | 其子类ValueAnimator 允许您将目标对象和对象属性设置为动画。此类在计算动画的新值时会相应地更新属性。您希望在ObjectAnimator 大多数情况下使用 它,因为它使得在目标对象上设置动画值的过程变得更加容易。但是,您有时希望ValueAnimator 直接使用,因为ObjectAnimator 还有一些限制,例如要求在目标对象上存在特定的acessor方法。 |
AnimatorSet | 提供一种将动画分组在一起的机制,以便它们相互运行。您可以将动画设置为一起播放,按顺序播放,或在指定的延迟播放后播放。 |
简单的实例演示ObjectAnimator的应用:(用button实现监听事件实现imageview动画效果)
case R.id.btn_move:
// move1();//简单的ObjectAnimator的使用
// move2();//用PropertyValuesHolder实现
move3();//用AnimatorSet实现
break;
/*
* propertyName:
* 若属性具有get()/set(),就可以通过属性动画操作此属性
* X/Y
* translationX/translationY
* rotation
* ...
* */
private void move1() {
// 第一个参数是所要操作的对象,第二个参数是操作的属性,第三个参数地范围变化
/*
* 此三个动画会同步执行
* <<<<<<<<<<<<<<<<<<<<<<<<<<<<<
* */
ObjectAnimator.ofFloat(imageView, "translationX", 0F, 200F).
setDuration(1000).
start();
ObjectAnimator.ofFloat(imageView, "translationY", 0F, 200F).
setDuration(1000).
start();
ObjectAnimator.ofFloat(imageView, "rotation", 0F, 360F).
setDuration(1000).
start();
/*
* 此三个动画会同步执行
* 调用start()方法后,为异步过程,所以三个动画同时起了作用
* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
* */
}
private void move2() {
/*
* 此方法利用PropertyValuesHolder实现多动画效果的共同实现
* 优点:比move1()方法,更有效率,同时节省资源
* */
PropertyValuesHolder p1 = PropertyValuesHolder
.ofFloat("rotation", 0, 360F);
PropertyValuesHolder p2 = PropertyValuesHolder
.ofFloat("translationY", 0, 360F);
PropertyValuesHolder p3 = PropertyValuesHolder
.ofFloat("translationX", 0, 360F);
ObjectAnimator.ofPropertyValuesHolder(imageView, p1, p2, p3)
.setDuration(1000)
.start();
}
private void move3() {
/*
* 利用动画集AnimatorSet实现多动画效果
* */
ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(imageView, "translationX", 0F, 200F);
ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(imageView, "translationY", 0F, 200F);
ObjectAnimator objectAnimator3 = ObjectAnimator.ofFloat(imageView, "rotation", 0F, 360F);
AnimatorSet animatorSet = new AnimatorSet();
// 用play()方法.with().after()可自定义动画顺序
// 同时执行多种动画效果
// animatorSet.playTogether(objectAnimator1,objectAnimator2,objectAnimator3);
// 顺序执行多种动画效果
animatorSet.playSequentially(objectAnimator1,objectAnimator2,objectAnimator3);
animatorSet
.setDuration(2000)
.start();
}
为动画添加监听事件(此实例为button自身添加了动画,并添加了监听事件)
case R.id.btn_click:
click(btn_click);
break;
...
private void click(View view) {
ObjectAnimator animator = ObjectAnimator.ofFloat(view, "alpha", 0F, 1F)
.setDuration(2000);
// 增加监听事件:方法一 用animator.addListener(new Animator.AnimatorListener()
// animator.addListener(new Animator.AnimatorListener() {
// @Override
// public void onAnimationStart(Animator animation) {
//
// }
//
// @Override
// public void onAnimationEnd(Animator animation) {
// Toast.makeText(MainActivity.this, "anim end", Toast.LENGTH_SHORT).show();
// }
//
// @Override
// public void onAnimationCancel(Animator animation) {
//
// }
//
// @Override
// public void onAnimationRepeat(Animator animation) {
//
// }
// });
// 增加监听事件:方法二 用animator.addListener(new AnimatorListenerAdapter()
// 减少无关的代码
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
Toast.makeText(MainActivity.this, "anim end", Toast.LENGTH_SHORT).show();
}
});
animator.start();
}
ValueAnimator
ValueAnimator包含Property Animation动画的所有核心功能,如动画时间,开始、结束属性值,相应时间属性值计算方法等。应用Property Animation有两个步聚:
ValuAnimiator只完成了第一步工作,如果要完成第二步,需要实现ValueAnimator.onUpdateListener接口,这个接口只有一个函数onAnimationUpdate(),在这个函数中会传入ValueAnimator对象做为参数,通过这个ValueAnimator对象的getAnimatedValue()函数可以得到当前的属性值。
/*
*用button中Text数值的增长监测ValueAnimator生成的数值
*/
public void click(View view){
final Button button = (Button) view;
ValueAnimator animator = ValueAnimator.ofInt(0, 100);
animator.setDuration(10000);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
Integer value = (Integer) animation.getAnimatedValue();
button.setText("" + value);
}
});
animator.start();
}
public void click(View view){
// 可以在ValueAnimator.ofObject(new TypeEvaluator()时,给TypeEvaluator指定一个泛型
ValueAnimator animator = ValueAnimator.ofObject(new TypeEvaluator() {
/*
* 重写evaluate,返回需要的值
* 第一个参数:0到1之间变化的时间因子
* */
@Override
public PointF evaluate(float fraction, PointF startValue, PointF endValue) {
return null;
}
});
}
Interpolator负责控制动画变化的速率,使得基本的动画效果能够以匀速、加速、减速、抛物线速率等各种速率变化。
画是开发者给定开始和结束的“关键帧”,其变化的“中间帧”是有系统计算决定然后播放出来。因此,动画的每一帧都将在开始和结束之间的特定时间显示。此时动画时间被转换为时间索引,则动画时间轴上的每个点都可以转换成0.0到1.0之间的一个浮点数。然后再将该值用于计算该对象的属性变换。
在变换的情况下,y轴上,0.0对应于起始位置,1.0对应于结束位置,0.5对应于起始和结束之间的中间,对于一些插值器其值还可以是0~1之外的数值。
视图动画系统提供仅为View
对象设置动画的功能,因此如果要为非View
对象设置动画,则必须实现自己的代码才能执行此操作。视图动画系统也受到约束,因为它仅将View
对象的一些方面暴露给动画,例如视图的缩放和旋转而不是背景颜色。
视图动画系统的另一个缺点是它只修改了绘制视图的位置,而不是实际的视图本身。例如,如果您设置了一个按钮以在屏幕上移动,则该按钮会正确绘制,但您可以单击该按钮的实际位置不会更改,因此您必须实现自己的逻辑来处理此问题。
使用属性动画系统,可以完全删除这些约束,并且可以为任何对象(视图和非视图)的任何属性设置动画,并且实际修改了对象本身。属性动画系统在执行动画方面也更加强大。在较高级别,您可以将动画师分配给要设置动画的属性,例如颜色,位置或大小,并可以定义动画的各个方面,例如多个动画师的插值和同步。
但是,视图动画系统设置时间较短,编写代码较少。如果视图动画完成了您需要执行的所有操作,或者现有代码已按您所需的方式工作,则无需使用属性动画系统。如果出现用例,将两种动画系统用于不同情况也是有意义的。