Android动画合集之补间动画

Android 动画合集之补间动画

补间动画(Tween Animation)是 Android 中一种经典的动画类型,通过定义视图(View)的初始和结束状态(如位置、透明度、旋转角度),由系统自动计算中间过渡帧来实现平滑动画效果。它基于 Animation 类及其子类(如 TranslateAnimationAlphaAnimation),适合简单的 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:重复模式(restartreverse)。
    • 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 组合多个动画,setInterpolatorsetDuration 可统一设置。
  • 各动画类(如 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*AsStateAnimatable 实现,基于属性动画思想:

  • 示例(透明度 + 缩放 + 旋转):
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 动画合集的其他部分(如属性动画、过渡动画)。

类似文章

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注