Android动画合集之补间动画
Android 动画合集之补间动画
补间动画(Tween Animation)是 Android 中一种经典的动画类型,通过定义视图(View)的初始和结束状态(如位置、透明度、旋转角度),由系统自动计算中间过渡帧来实现平滑动画效果。它基于 Animation
类及其子类(如 TranslateAnimation
、AlphaAnimation
),适合简单的 UI 动画场景,如平移、缩放、旋转或淡入淡出。本文将详细介绍补间动画的实现方式、类型、配置方法、优缺点及实际应用,作为 Android 动画合集的一部分(前文已覆盖帧动画)。
补间动画的原理与作用
- 原理:补间动画通过定义动画的起点和终点属性(如位置、透明度),结合插值器(Interpolator)和持续时间,系统自动生成中间状态并应用到 View 上。它不修改 View 的实际属性(如 layout 位置),仅改变绘制效果(即视觉上的变换)。补间动画通过
Animation
类和 XML 或代码配置实现,底层依赖Canvas
的矩阵变换。 - 作用:提供简单、高效的视觉动画,适合快速实现 UI 过渡效果,而无需复杂的属性计算。
- 应用场景:
- 按钮点击时的缩放或抖动效果。
- 页面切换的滑入/滑出动画。
- 淡入淡出(如欢迎页渐显)。
- 旋转加载图标或翻转卡片效果。
补间动画的类型
补间动画由 Animation
类的子类实现,常见类型包括以下四种:
动画类型 | 类名 | 描述 | 示例效果 |
---|---|---|---|
AlphaAnimation | 透明度动画 | 改变 View 的透明度(0.0f 完全透明,1.0f 完全不透明)。 | 淡入淡出 |
ScaleAnimation | 缩放动画 | 改变 View 的大小(缩放比例),可指定缩放中心点。 | 放大缩小 |
RotateAnimation | 旋转动画 | 围绕指定轴点旋转 View(角度变化)。 | 图标旋转 |
TranslateAnimation | 平移动画 | 移动 View 的位置(水平/垂直位移)。 | 滑入滑出 |
AnimationSet | 动画集合 | 组合多个动画(如透明+缩放),支持同步或顺序播放。 | 复杂组合 |
实现补间动画的两种方式
补间动画可以通过 XML 资源文件 或 代码动态创建 来实现。以下分别介绍。
1. 使用 XML 资源文件
补间动画通常在 res/anim
目录下定义 XML 文件,使用 <alpha>
、<scale>
、<rotate>
、<translate>
或 <set>
标签配置。
- XML 示例(res/anim/sample_animation.xml):
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1000"
android:interpolator="@android:anim/accelerate_decelerate_interpolator">
<!-- 透明度动画:从完全透明到完全不透明 -->
<alpha
android:fromAlpha="0.0"
android:toAlpha="1.0" />
<!-- 缩放动画:从 0.5 倍放大到 1 倍,中心为 View 中心 -->
<scale
android:fromXScale="0.5"
android:fromYScale="0.5"
android:toXScale="1.0"
android:toYScale="1.0"
android:pivotX="50%"
android:pivotY="50%" />
<!-- 旋转动画:从 0 度旋转到 360 度 -->
<rotate
android:fromDegrees="0"
android:toDegrees="360"
android:pivotX="50%"
android:pivotY="50%" />
<!-- 平移动画:从左侧 100px 移到原位 -->
<translate
android:fromXDelta="-100"
android:toXDelta="0"
android:fromYDelta="0"
android:toYDelta="0" />
</set>
- 常用属性:
android:duration
:动画持续时间(毫秒)。android:interpolator
:插值器(如@android:anim/linear_interpolator
)。android:startOffset
:延迟开始时间(毫秒)。android:repeatCount
:重复次数(-1 为无限,整数为具体次数)。android:repeatMode
:重复模式(restart
或reverse
)。android:fillAfter
:动画结束后是否保持最终状态(true 保持,false 恢复)。
- 在代码中使用:
import android.os.Bundle;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.Button;
import android.widget.ImageView;
import androidx.appcompat.app.AppCompatActivity;
public class TweenAnimationActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tween_animation);
ImageView imageView = findViewById(R.id.image_view);
Button startButton = findViewById(R.id.start_button);
// 加载动画
Animation animation = AnimationUtils.loadAnimation(this, R.anim.sample_animation);
// 按钮触发动画
startButton.setOnClickListener(v -> imageView.startAnimation(animation));
}
}
- 布局 XML(res/layout/activity_tween_animation.xml):
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:id="@+id/image_view"
android:layout_width="100dp"
android:layout_height="100dp"
android:src="@drawable/ic_launcher_foreground" />
<Button
android:id="@+id/start_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Start Animation" />
</LinearLayout>
2. 使用代码动态创建
通过 Animation
子类动态配置动画,适合运行时调整参数。
- 代码示例:
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.Button;
import android.widget.ImageView;
import androidx.appcompat.app.AppCompatActivity;
public class TweenAnimationActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tween_animation);
ImageView imageView = findViewById(R.id.image_view);
Button startButton = findViewById(R.id.start_button);
// 创建动画集合
AnimationSet animationSet = new AnimationSet(true); // true 表示共享插值器
animationSet.setDuration(1000);
animationSet.setInterpolator(new android.view.animation.AccelerateDecelerateInterpolator());
// 透明度动画
AlphaAnimation alpha = new AlphaAnimation(0.0f, 1.0f);
animationSet.addAnimation(alpha);
// 缩放动画
ScaleAnimation scale = new ScaleAnimation(0.5f, 1.0f, 0.5f, 1.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
animationSet.addAnimation(scale);
// 旋转动画
RotateAnimation rotate = new RotateAnimation(0, 360, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
animationSet.addAnimation(rotate);
// 平移动画
TranslateAnimation translate = new TranslateAnimation(-100, 0, 0, 0);
animationSet.addAnimation(translate);
// 按钮触发动画
startButton.setOnClickListener(v -> imageView.startAnimation(animationSet));
}
}
- 说明:
AnimationSet
组合多个动画,setInterpolator
和setDuration
可统一设置。- 各动画类(如
AlphaAnimation
)支持单独配置参数。 - 参数如
RELATIVE_TO_SELF
表示相对自身坐标(如 pivotX=0.5f 表示 View 宽度的一半)。
关键方法与属性
以下是 Animation
及其子类的核心方法和属性:
方法/属性 | 描述 | 用法示例 |
---|---|---|
startAnimation(Animation) | 在 View 上启动动画。 | view.startAnimation(animation); |
clearAnimation() | 停止 View 的动画。 | view.clearAnimation(); |
setDuration(long) | 设置动画持续时间(毫秒)。 | animation.setDuration(1000); |
setInterpolator(Interpolator) | 设置插值器,控制动画速度曲线。 | animation.setInterpolator(new LinearInterpolator()); |
setRepeatCount(int) | 设置重复次数(-1 为无限)。 | animation.setRepeatCount(Animation.INFINITE); |
setRepeatMode(int) | 设置重复模式(RESTART 或 REVERSE)。 | animation.setRepeatMode(Animation.REVERSE); |
setFillAfter(boolean) | 动画结束后是否保持最终状态。 | animation.setFillAfter(true); |
setAnimationListener(AnimationListener) | 设置动画监听器(开始、结束、重复)。 | animation.setAnimationListener(listener); |
插值器(Interpolator)
插值器控制动画的时间-值曲线,常见内置插值器包括:
LinearInterpolator
:匀速。AccelerateDecelerateInterpolator
:先加速后减速(默认)。BounceInterpolator
:弹跳效果。OvershootInterpolator
:超出后回弹。- 自定义插值器:实现
Interpolator
接口或使用TimeInterpolator
。
优缺点
- 优点:
- 配置简单,XML 和代码均支持,易上手。
- 性能较高(基于矩阵变换,适合简单动画)。
- 支持组合动画,灵活性较高。
- 缺点:
- 仅影响 View 的绘制效果,不改变实际属性(如 layout 位置)。
- 不支持复杂动画(如非线性路径或动态属性变化)。
- 对交互性支持有限(动画期间 View 位置不变,点击区域不随动画移动)。
- 替代方案:
- 属性动画(Property Animation):更灵活,支持修改 View 实际属性(API 11+)。
- Lottie:适合复杂矢量动画。
- Jetpack Compose 动画:声明式动画,现代化替代。
注意事项
- 性能:补间动画性能较高,但大量动画或复杂组合可能影响主线程。建议避免在列表项中重复使用。
- 生命周期:在 Activity/Fragment 暂停时(如
onPause
)调用clearAnimation()
释放资源。 - 兼容性:补间动画自 API 1 支持,无需额外权限。
- 交互性:由于不修改 View 实际位置,动画期间点击区域可能不符合预期(考虑属性动画解决)。
- 调试:使用
AnimationListener
监听动画状态,或通过 Log 输出动画进度。
扩展:Jetpack Compose 中的等效实现
在 Jetpack Compose 中,补间动画通过 animate*AsState
或 Animatable
实现,基于属性动画思想:
- 示例(透明度 + 缩放 + 旋转):
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.tween
import androidx.compose.foundation.Image
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
@Composable
fun TweenAnimation() {
var enabled by remember { mutableStateOf(false) }
val alpha by animateFloatAsState(
targetValue = if (enabled) 1f else 0f,
animationSpec = tween(durationMillis = 1000)
)
val scale by animateFloatAsState(
targetValue = if (enabled) 1f else 0.5f,
animationSpec = tween(durationMillis = 1000)
)
val rotation by animateFloatAsState(
targetValue = if (enabled) 360f else 0f,
animationSpec = tween(durationMillis = 1000)
)
Image(
painter = painterResource(id = R.drawable.ic_launcher_foreground),
contentDescription = "Tween Animation",
modifier = Modifier
.size(100.dp)
.graphicsLayer(
alpha = alpha,
scaleX = scale,
scaleY = scale,
rotationZ = rotation
)
.clickable { enabled = !enabled }
)
}
- 说明:使用
animateFloatAsState
实现透明度、缩放和旋转,tween
指定持续时间和曲线。Compose 动画更灵活,支持实际属性修改。
示例:页面滑入动画
一个常见的页面滑入效果:
<!-- res/anim/slide_in.xml -->
<translate
xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXDelta="-100%"
android:toXDelta="0"
android:duration="500"
android:interpolator="@android:anim/decelerate_interpolator" />
View view = findViewById(R.id.container);
Animation slideIn = AnimationUtils.loadAnimation(this, R.anim.slide_in);
view.startAnimation(slideIn);
如果需要更多补间动画示例(如复杂 AnimationSet 组合、自定义插值器)、与属性动画的对比、Lottie 替代方案,或 Compose 中的高级动画实现,请告诉我!后续可继续探讨 Android 动画合集的其他部分(如属性动画、过渡动画)。