Android动画——补间动画

简介: 继续上一章,本章说下Tween Animation。Twen Animation相对简单,它可以支持简单的缩放、平移、旋转、透明度渐变的动画。
继续上一章,本章说下Tween Animation。Twen Animation相对简单,它可以支持简单的缩放、平移、旋转、透明度渐变的动画。补间动画与逐帧动画的不同之处就在于,补间动画只需要指定动画的开始、结束“关键帧”,而动画变化的的“中间帧”由系统计算、并补齐,包括四个子类:
  • AlphaAnimation:透明度改变的动画,创建时需要制定动画开始时的透明度、结束时的透明度和动画持续时间,其中透明度变化范围0.0——1.0。
  • RotateAnimation:旋转动画,创建时需要制定动画开始时的旋转角度、结束时的旋转角度和动画持续时间。由于旋转时以不同点为中心时旋转效果并不相同,因此需要指定旋转动画还要通过pivoX、pivoY来指定“旋转轴心的坐标”。
  • ScaleAnimation:缩放动画,创建时需要制定动画开始时的缩放比(以X、Y轴的缩放参数来表示)、结束时动画的缩放比(以X、Y轴的缩放参数来表示)和动画持续时间。由于缩放时以不同点为中心时缩放效果并不相同,因此需要指定缩放动画还要通过pivoX、pivoY来指定“缩放中心的坐标”。
  • TranslateAnimation:位移变化动画,创建时需要制定动画开始时的位置(以X、Y坐标来表示)、结束时的位置(以X、Y坐标来表示表示)和动画持续时间。

Tween Animation的效果由四个因素决定:1)开始帧;2)结束帧;3)持续时间;4)Interpolator。所以要定义一个View Animation,你只要定义以上四个因素,中间的过程怎么变化则由系统自动计算出来。第四个因素Interpolator比较特别,Interpolator是为了控制在动画期间需要动态“补入”多少帧,并计算所有补入帧的图形以及在哪些时刻补入。比如:你将一个按钮从屏幕左侧运动到屏幕右侧。可以让它一直加速前进,或者先加速然后减速,这就是Interpolator发挥的作用,具体使用方法下面会说。像Drawable Animation一样,定义一个View Animation可以用代码的方式,也可以用XML文件的方式,Tween Animation的xml文件的格式如下:
<?xml version="1.0" encoding="utf-8"?>  
<setxmlns:androidsetxmlns:android="http://schemas.android.com/apk/res/android"  
    android:interpolator="@[package:]anim/interpolator_resource"  
    android:shareInterpolator=["true" | "false"] >  
    <alpha  
        android:fromAlpha="float"  
        android:toAlpha="float"/>  
    <scale  
        android:fromXScale="float"  
        android:toXScale="float"  
        android:fromYScale="float"  
        android:toYScale="float"  
        android:pivotX="float"  
        android:pivotY="float"/>  
    <translate  
        android:fromXDelta="float"  
        android:toXDelta="float"  
        android:fromYDelta="float"  
        android:toYDelta="float"/>  
    <rotate  
        android:fromDegrees="float"  
        android:toDegrees="float"  
        android:pivotX="float"  
        android:pivotY="float"/>  
    <set>  
        ...  
    </set>  
</set>  
xml文件中必须有一个根元素,使用 <alpha>, <scale>, <translate>, <rotate>, 或者 <set>。<set>作为根元素可以包含<alpha>, <scale>, <translate>, <rotate>中的一个或多个,也可以包含多个子<set>。

下面先说下各个元素共有的属性,然后再分别说下各自的属性

duration:动画从初始状态到最终状态的持续时间repeatCount:不包括第一次显示的,显示次数
interpolator(插值器):应用于动画的插值器。该值必须是一个指定了插值器资源的引用(不是一个插值器的类名),在平台中有缺省的插值器资源可以使用,也可以自定义插值器资源
repeatMode:动画重复模式
fillAfter:通过设置fillAfter为true,则动画将保持结束的状态
startOffset:该属性定义动画推迟多久开始,通过这个属性的设置,我们可以设计一些前后按序发生的动画,当然,除了最后一个发生的动画,其他动画得设置fillAfter为true.

<set>
一个持有其它动画元素的容器(<alpha>, <scale>, <translate>, <rotate>) 或者其它 <set> 元素),代表一个动画集合
属性
shareInterpolator:是否将该Interpolator共享给子节点,为 true代表在所有的子元素中共享同一个插值器

<alpha>
A fade-in or fade-out animation. Represents an AlphaAnimation.
一个渐入渐出的动画,对应的java类为AlphaAnimation。
属性
fromAlpha:动画的初始透明度
toAlpha:动画结束时透明度
0.0表示完全透明,1.0表示完全不透明,Float值

<scale>
可以实现动态调控件尺寸的效果,通过设置pivotX和pivotY你可以指定image缩放的中心点,比如:如果这些值是0,则表示左上角,所有的缩放变化将沿着右下角的轨迹运动。对应的类为ScaleAnimation
属性
fromXScale:动画初始时X轴的伸缩比例,0.0表示收缩到没有,1.0表示正常无伸缩
toXScale:动画结束时X轴的伸缩比例
fromYScale:动画初始时Y轴的伸缩比例
toYScale动画结束时Y轴的伸缩比例
这四个属性代表动画起始或者结束X / Y方向上的缩放比例,使用Float值或者num%、num%p
pivotX和pivotY,我们知道,pivot的意思是轴心的意思,所以这两个属性定义的是此次动画变化的轴心位置,默认是左上角,当我们把它们两者都赋值为0.5或者50%,则变化轴心在中心。

<translate>
代表一个水平、垂直的位移,对应的类为TranslateAnimation.
属性
fromXDelta:动画起始X轴的坐标
toXDelta:动画结束时X轴的坐标
fromYDelta:动画起始Y轴的坐标
toYDelta:动画结束时Y轴的坐标
这四个属性代表动画起始或者结束X / Y方向上的位置,使用Float值或者百分比值,浮点数num%、num%p分别相对于自身或者父控件。如果以浮点数字表示,是一个绝对值,代表相对自身原始位置的像素值;如果以num%表示,代表相对于自己的百分比,比如toXDelta定义为100%就表示在X方向上移动自己的1倍距离;如果以num%p表示,代表相对于父类组件的百分比。

<rotate> 
旋转动画,与之对应的Java类是RotateAnimation。
属性
fromDegrees:动画初始时的角度,浮点值,单位:度
toDegrees:动画结束时的角度
pivotX 属性代表旋转中心的X坐标值
pivotY 属性代表旋转中心的Y坐标值
Float值或者百分比,这两个属性也有三种表示方式,但是X轴都是相对方向都是Left,Y轴都是相对于Top,使用浮点数、num%、num%p;浮点数代表相对于自身左边缘的像素值;num%方式代表相对于自身左边缘或顶边缘的百分比;num%p方式代表相对于父容器的左边缘或顶边缘的百分比。

下面我们写一个例子,说明下XML的定义方式,同时也说明下Java的实现方式,好了,上代码
  • 首先是anim_alpha.xml,定义一个实现透明渐变的动画该动画实现的是完全不透明——>完全透明——>完全不透明
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_interpolator"
android:duration="2000"
android:fillAfter="true"
android:fromAlpha="1.0"
android:repeatCount="1"
android:repeatMode="reverse"
android:toAlpha="0.0" />

  • 创建名称是anim_rotate.xml,定义一个实现旋转的动画,实现从零到720度的旋转
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="2000"
android:fromDegrees="0"
android:interpolator="@android:anim/accelerate_interpolator"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="720" />

  • 创建名称是anim_scale.xml的文件,定义一个实现缩放的动画,该动画首先将原来的图像放大两倍再将其缩小到原来的尺寸
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="2000"
android:fillAfter="true"
android:fromXScale="1.0"
android:fromYScale="1.0"
android:interpolator="@android:anim/decelerate_interpolator"
android:pivotX="50%"
android:pivotY="50%"
android:repeatCount="1"
android:repeatMode="reverse"
android:toXScale="2.0"
android:toYScale="2.0" />

  • 创建名称是anim_translate.xml的文件,实现图片的平移从左侧移动到右侧然后从右侧移动到左侧
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="2000"
android:fillAfter="true"
android:fromXDelta="0"
android:fromYDelta="0"
android:interpolator="@android:anim/accelerate_interpolator"
android:toXDelta="400"
android:toYDelta="0" />

  • 创建名称是anim_set.xml的文件,将几个动画效果综合一下
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >

<alpha
android:duration="2000"
android:fillAfter="true"
android:fromAlpha="1"
android:repeatCount="1"
android:repeatMode="reverse"
android:toAlpha="0" />

<rotate
android:duration="2000"
android:fromDegrees="0"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="720" />

<scale
android:duration="2000"
android:fillAfter="true"
android:fromXScale="1"
android:fromYScale="1"
android:pivotX="50%"
android:pivotY="50%"
android:repeatCount="1"
android:repeatMode="reverse"
android:toXScale="2.0"
android:toYScale="2.0" />

</set>

布局很简单,相信一看效果就明白,我们就不说了,看下java代码
public class TweenAnimationActivity extends Activity {
private ImageView mImageView;
private Button[] mButtons = new Button[10];
private int[] mIndexs = { R.id.btn_tween_alpha, R.id.btn_tween_rotate,
R.id.btn_tween_scale, R.id.btn_tween_translate, R.id.btn_tween_set,
R.id.btn_tween_alpha1, R.id.btn_tween_rotate1, R.id.btn_tween_scale1,
R.id.btn_tween_translate1, R.id.btn_tween_set1 };
private Animation alphaAnimation;
private Animation rotateAnimation;
private Animation scaleAnimation;
private Animation setAnimation;
private Animation translateAnimation;
/**
* 使用java方式创建的动画
*/
private Animation alphaAnimation1;
private Animation rotateAnimation1;
private Animation scaleAnimation1;
private Animation translateAnimation1;
private Animation setAnimation1;
private ButtonListener mListener;

@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tween_animation);

initViews();
initAnimation();
}

private void initViews() {
mImageView = (ImageView) findViewById(R.id.iv_tween_img);
mListener = new ButtonListener();
for (int i = 0; i < 10; i++) {
mButtons[i] = (Button) findViewById(mIndexs[i]);
mButtons[i].setOnClickListener(mListener);
}
}

private void initAnimation() {
/**
* 获得xml定义的动画
*/
alphaAnimation = AnimationUtils.loadAnimation(this, R.anim.anim_alpha);
rotateAnimation = AnimationUtils
.loadAnimation(this, R.anim.anim_rotate);
scaleAnimation = AnimationUtils.loadAnimation(this, R.anim.anim_scale);
setAnimation = AnimationUtils.loadAnimation(this, R.anim.anim_set);
translateAnimation = AnimationUtils.loadAnimation(this,
R.anim.anim_translate);
/**
* 使用java方式创建的动画
*/
setAnimation1 = new AnimationSet(true);//创建一个动画集合
alphaAnimation1 = new AlphaAnimation(1.0f, 0.0f);// 从不透明变为全透明
rotateAnimation1 = new RotateAnimation(0, 720);// 顺时针旋转720度
scaleAnimation1 = new ScaleAnimation(1, 2, 1, 2);// 横向、纵向放大一倍
translateAnimation1 = new TranslateAnimation(0, 400, 0, 0);// 横向位移400单位
setAnimation1.addAnimation(alphaAnimation1);
setAnimation1.addAnimation(rotateAnimation1);
setAnimation1.addAnimation(scaleAnimation1);
setAnimation1.addAnimation(translateAnimation1);
// 设置持续时间
alphaAnimation1.setDuration(2000);
rotateAnimation1.setDuration(2000);
scaleAnimation1.setDuration(2000);
translateAnimation1.setDuration(2000);
setAnimation1.setDuration(2000);
// 设置Interpolator
alphaAnimation1.setInterpolator(new AccelerateDecelerateInterpolator());
rotateAnimation1
.setInterpolator(new AccelerateDecelerateInterpolator());
scaleAnimation1.setInterpolator(new AccelerateDecelerateInterpolator());
translateAnimation1
.setInterpolator(new AccelerateDecelerateInterpolator());

}

private class ButtonListener implements OnClickListener {

@Override
public void onClick(View v) {
//清除之前的动画
mImageView.clearAnimation();
switch (v.getId()) {
case R.id.btn_tween_alpha:
mImageView.startAnimation(alphaAnimation);
break;
case R.id.btn_tween_rotate:
mImageView.startAnimation(rotateAnimation);
break;
case R.id.btn_tween_scale:
mImageView.startAnimation(scaleAnimation);
break;
case R.id.btn_tween_set:
mImageView.startAnimation(setAnimation);
break;
case R.id.btn_tween_translate:
mImageView.startAnimation(translateAnimation);
break;
case R.id.btn_tween_alpha1:
mImageView.startAnimation(alphaAnimation1);
break;
case R.id.btn_tween_rotate1:
mImageView.startAnimation(rotateAnimation1);
break;
case R.id.btn_tween_scale1:
mImageView.startAnimation(scaleAnimation1);
break;
case R.id.btn_tween_set1:
mImageView.startAnimation(setAnimation1);
break;
case R.id.btn_tween_translate1:
mImageView.startAnimation(translateAnimation1);
break;

default:
System.out.println(">>>>>");
break;
}
}

}
}
效果如下:


好了,我们着重说下补间动画一个特殊的属性
Interpolators
插值器可以让动画按照一定的频率运动,实现加速、加速、重复、回弹等效果。常用插值器及使用:

可以通过下面的方式使用它们
<set android:interpolator="@android:anim/accelerate_interpolator">  
        ...  
</set> 
 
自定义插值器
如果你对系统提供的插值器不满意,我们可以创建一个插值器资源修改插值器的属性,比如修改AnticipateInterpolator的加速速率,调整CycleInterpolator的循环次数等。为了完成这种需求,我们需要创建XML资源文件,然后将其放于/res/anim下,然后再动画元素中引用即可。个性化插值器语法:
<?xml version="1.0" encoding="utf-8"?>  
<InterpolatorName xmlns:android="http://schemas.android.com/apk/res/android"  
    android:attribute_name="value"  
    />  
我们先来看一下几种常见的插值器可调整的属性:
<accelerateDecelerateInterpolator> 无
<accelerateInterpolator> android:factor 浮点值,加速速率,默认为1
<anticipateInterploator> android:tension 浮点值,起始点后退的张力、拉力数,默认为2
<anticipateOvershootInterpolator> android:tension 同上 android:extraTension 浮点值,拉力的倍数,默认为1.5(2  * 1.5)
<bounceInterpolator> 无
<cycleInterplolator> android:cycles int,循环的个数,默认为1
<decelerateInterpolator> android:factor 浮点值,减速的速率,默认为1
<linearInterpolator> 无
<overshootInterpolator> 浮点值,超出终点后的张力、拉力,默认为2

下面举个个性化插值器的例子,XML 文件存放在:res/anim/目录下,
<?xml version="1.0" encoding="utf-8"?>  
<customInterpolator xmlns:android="http://schemas.android.com/apk/res/android"  
    android:tension="7.0"  
    />  
个性化插值器使用:
<scale xmlns:android="http://schemas.android.com/apk/res/android"  
    android:interpolator="@anim/my_overshoot_interpolator"  
    android:fromXScale="1.0"  
    android:toXScale="3.0"  
    android:fromYScale="1.0"  
    android:toYScale="3.0"  
    android:pivotX="50%"  
    android:pivotY="50%"  
    android:duration="700" />  

总结:
如果你的需求中只需要对View进行移动、缩放、旋转和淡入淡出操作,那么补间动画确实已经足够健全了。但是很显然,这些功能是不足以覆盖所有的场景的,一旦我们的需求超出了移动、缩放、旋转和淡入淡出这四种对View的操作,那么补间动画就不能再帮我们忙了,也就是说它在功能和可扩展方面都有相当大的局限性,也就是说,我们可以对一个Button、TextView、甚至是LinearLayout、或者其它任何继承自View的组件进行动画操作,但是如果我们想要对一个非View的对象进行动画操作,补间动画就帮不上忙了。可能有的朋友会感到不能理解为什么要对一个非View的对象进行动画操作。这里我举一个简单的例子,比如说我们有一个自定义的View,在这个View当中有一个Point对象用于管理坐标,然后在onDraw()方法当中就是根据这个Point对象的坐标值来进行绘制的。也就是说,如果我们可以对Point对象进行动画操作,那么整个自定义View的动画效果就有了。显然,补间动画是不具备这个功能的,这是它的第一个缺陷。
然后补间动画还有一个缺陷,就是它只能够实现移动、缩放、旋转和淡入淡出这四种动画操作,那如果我们希望可以对View的背景色进行动态地改变呢?很遗憾,我们只能靠自己去实现了。说白了,之前的补间动画机制就是使用硬编码的方式来完成的,功能限定死就是这些,基本上没有任何扩展性可言。
最后,补间动画还有一个致命的缺陷,就是它只是改变了View的显示效果而已,而不会真正去改变View的属性值。什么意思呢?比如说,现在屏幕的左上角有一个按钮,然后我们通过补间动画将它移动到了屏幕的右下角,现在你可以去尝试点击一下这个按钮,点击事件是绝对不会触发的,因为 它只是改变了View对象绘制的位置,而没有改变View对象本身,该组件真正的位置依然保留在原来的位置,实际上这个按钮还是停留在屏幕的左上角,只不过补间动画将这个按钮绘制到了屏幕的右下角而已,所以想真正移动某组件,需要在动画结束后添加代码实现。

参考:

相关文章
|
4月前
|
存储 Shell Android开发
基于Android P,自定义Android开机动画的方法
本文详细介绍了基于Android P系统自定义开机动画的步骤,包括动画文件结构、脚本编写、ZIP打包方法以及如何将自定义动画集成到AOSP源码中。
79 2
基于Android P,自定义Android开机动画的方法
|
2月前
|
Android开发 UED
Android 中加载 Gif 动画
【10月更文挑战第20天】加载 Gif 动画是 Android 开发中的一项重要技能。通过使用第三方库或自定义实现,可以方便地在应用中展示生动的 Gif 动画。在实际应用中,需要根据具体情况进行合理选择和优化,以确保用户体验和性能的平衡。可以通过不断的实践和探索,进一步掌握在 Android 中加载 Gif 动画的技巧和方法,为开发高质量的 Android 应用提供支持。
|
7月前
|
Java Android开发 开发者
Android10 修改开发者选项中动画缩放默认值
Android10 修改开发者选项中动画缩放默认值
199 0
|
7月前
|
XML Java Android开发
android的三种动画
android的三种动画
38 0
|
5月前
|
XML Android开发 数据格式
Android 中如何设置activity的启动动画,让它像dialog一样从底部往上出来
在 Android 中实现 Activity 的对话框式过渡动画:从底部滑入与从顶部滑出。需定义两个 XML 动画文件 `activity_slide_in.xml` 和 `activity_slide_out.xml`,分别控制 Activity 的进入与退出动画。使用 `overridePendingTransition` 方法在启动 (`startActivity`) 或结束 (`finish`) Activity 时应用这些动画。为了使前 Activity 保持静止,可定义 `no_animation.xml` 并在启动新 Activity 时仅设置新 Activity 的进入动画。
124 12
|
5月前
|
XML Android开发 UED
Android动画之共享元素动画简单实践
本文介绍Android共享元素动画, 实现两Activity间平滑过渡特定UI元素。通过设置`transitionName`属性和使用`ActivityOptions.makeSceneTransitionAnimation`启动目标Activity实现动画效果。可自定义过渡动画提升体验。
75 0
|
6月前
|
Android开发 UED
Android Item平移动画
【6月更文挑战第18天】
113 8
|
5月前
|
Android开发
android 动画 插值器和估值器
android 动画 插值器和估值器
|
7月前
|
数据库 Android开发
Android数据库框架-GreenDao入门,2024年最新flutter 页面跳转动画
Android数据库框架-GreenDao入门,2024年最新flutter 页面跳转动画
Android数据库框架-GreenDao入门,2024年最新flutter 页面跳转动画