Android 补间动画基础:位移、缩放、旋转与透明度详解
概述
在 Android 开发中,补间动画(Tween Animation)是一种通过改变视图的几何属性来实现视觉过渡效果的技术。它主要用于处理视图在位移、缩放、旋转和透明度方面的变化。虽然现代 Android 开发更推荐使用属性动画(Property Animation),但理解补间动画对于维护旧项目或实现特定简单效果仍然至关重要。
补间动画的核心在于定义一个初始状态和一个结束状态,系统会自动计算中间帧的变化过程。本文详细讲解四种基本补间动画类型的参数设置、配置方法以及组合使用的技巧。
核心概念
补间动画类位于 android.view.animation 包下。主要包含以下四个子类:
- TranslateAnimation:控制视图的位置移动。
- ScaleAnimation:控制视图的大小缩放。
- AlphaAnimation:控制视图的透明度变化。
- RotateAnimation:控制视图的旋转角度。
这些动画可以通过 AnimationSet 进行组合,同时执行多个动画效果。
TranslateAnimation 位移动画
位移动画用于改变视图在屏幕上的位置。构造器接受四个浮点数参数,分别代表 X 轴起点、X 轴终点、Y 轴起点、Y 轴终点。
坐标系统
参数可以是绝对值,也可以是相对值。相对值通常使用常量如 Animation.RELATIVE_TO_SELF。
- 绝对坐标:直接指定像素值。例如
new TranslateAnimation(10, 150, ...) 表示从 X=10 移动到 X=150。
- 相对坐标:相对于视图自身的尺寸。
- 若传入
0.5f,则坐标为 真实 X + 0.5 * 宽度。
- 若传入
2,则坐标为 真实 X + 2 * 宽度。
示例代码:
TranslateAnimation ta = new TranslateAnimation(
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 2,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 2
);
ScaleAnimation 缩放动画
缩放动画用于改变视图的宽高比。构造器同样接受四个参数,分别对应 X 轴起始比例、X 轴结束比例、Y 轴起始比例、Y 轴结束比例。
中心点控制
默认情况下,缩放中心点位于视图的左上角。为了视觉效果更佳,通常需要指定缩放中心点。
- 无中心点参数:默认左上角。
- 有中心点参数:添加两个额外参数指定 PivotX 和 PivotY。
- 使用
Animation.RELATIVE_TO_SELF 配合 0.5f 可实现以视图中心为基准缩放。
示例代码:
ScaleAnimation sa = new ScaleAnimation(
0.1f, 4,
0.1f, 4,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f
);
AlphaAnimation 透明度动画
透明度动画控制视图的不透明度。参数范围是 0.0 到 1.0。
- 0.0:完全透明(不可见)。
- 1.0:完全不透明(可见)。
示例代码:
AlphaAnimation aa = new AlphaAnimation(0, 0.5f);
RotateAnimation 旋转动画
旋转动画控制视图绕某一点旋转的角度。参数单位为度(Degree)。
默认旋转中心为左上角。建议指定中心点以实现围绕中心的旋转。
示例代码:
RotateAnimation ra = new RotateAnimation(
20, 360,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f
);
动画配置方法
创建动画对象后,需要通过一系列方法进行配置,以控制播放行为。
持续时间
ta.setDuration(2000);
重复次数与模式
ta.setRepeatCount(1);
ta.setRepeatMode(Animation.REVERSE);
填充策略
ta.setFillAfter(true);
启动动画
iv.startAnimation(ta);
AnimationSet 动画集合
当需要同时执行多个动画时,使用 AnimationSet。构造函数中的布尔值参数决定是否共享插值器。
AnimationSet set = new AnimationSet(false);
set.addAnimation(aa);
set.addAnimation(sa);
set.addAnimation(ra);
iv.startAnimation(set);
完整代码示例
布局文件 (activity_main.xml)
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/iv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_launcher"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:layout_alignParentBottom="true"
android:orientation="horizontal">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="平移"
android:onClick="translate" />
<Button
android:layout_width=
=
=
= />
Activity 代码 (MainActivity.java)
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.RotateAnimation;
import android.view.animation.ScaleAnimation;
import android.view.animation.TranslateAnimation;
import android.widget.ImageView;
public class MainActivity extends Activity {
private ImageView iv;
private TranslateAnimation ta;
private ScaleAnimation sa;
private AlphaAnimation aa;
private RotateAnimation ra;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
iv = findViewById(R.id.iv);
}
public void translate(View view) {
ta = new TranslateAnimation(
Animation.RELATIVE_TO_SELF, -1,
Animation.RELATIVE_TO_SELF, 2,
Animation.RELATIVE_TO_SELF, -0.5f,
Animation.RELATIVE_TO_SELF, 1.5f
);
ta.setDuration(2000);
ta.setRepeatCount(1);
ta.setRepeatMode(Animation.REVERSE);
iv.startAnimation(ta);
}
public void scale {
sa = (
, , , ,
Animation.RELATIVE_TO_SELF, ,
Animation.RELATIVE_TO_SELF,
);
sa.setDuration();
sa.setRepeatCount();
sa.setRepeatMode(Animation.ABSOLUTE);
sa.setFillAfter();
iv.startAnimation(sa);
}
{
aa = (, );
aa.setDuration();
aa.setRepeatCount();
aa.setRepeatMode(Animation.REVERSE);
iv.startAnimation(aa);
}
{
ra = (
, ,
Animation.RELATIVE_TO_SELF, ,
Animation.RELATIVE_TO_SELF,
);
ra.setDuration();
ra.setRepeatCount();
ra.setRepeatMode(Animation.REVERSE);
ra.setFillAfter();
iv.startAnimation(ra);
}
{
();
set.addAnimation(ta);
set.addAnimation(sa);
set.addAnimation(aa);
set.addAnimation(ra);
iv.startAnimation(set);
}
}
高级用法与注意事项
插值器 (Interpolator)
插值器决定了动画速度随时间变化的曲线。默认是线性插值,感觉生硬。常用的有 AccelerateDecelerateInterpolator(先加速后减速)和 OvershootInterpolator(超出目标再回弹)。
ta.setInterpolator(new AccelerateDecelerateInterpolator());
动画监听器 (AnimationListener)
通过实现 Animation.AnimationListener 接口,可以监听动画的开始、重复和结束事件。
ta.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {}
@Override
public void onAnimationEnd(Animation animation) {
}
@Override
public void onAnimationRepeat(Animation animation) {}
});
性能优化建议
- 避免频繁创建对象:尽量复用动画对象,减少 GC 压力。
- 慎用 FillAfter:如果不需要视图停留在动画位置,不要开启此选项,否则可能影响后续布局计算。
- 考虑替代方案:对于复杂交互,建议使用
ViewPropertyAnimator 或 ObjectAnimator,它们基于属性动画,性能更好且支持硬件加速。
常见问题排查
- 动画不显示:检查
FillAfter 是否被正确设置,或者视图是否被其他 View 遮挡。
- 坐标偏移:注意相对坐标是基于父容器还是自身,确保计算逻辑符合预期。
- 内存泄漏:在 Activity 销毁前停止正在运行的动画,防止持有 Context 引用。
总结
补间动画是 Android 早期版本中主要的动画解决方案。掌握其原理和 API 有助于开发者理解视图变换机制。尽管在新项目中应优先考虑属性动画,但在兼容旧版设备或实现简单特效时,补间动画依然具有实用价值。通过合理配置参数和组合使用,可以实现丰富的视觉反馈效果。