android View详解—动画

旋转动画

一、使用 XML 方式(推荐)

1. 创建动画文件

在 res/anim 目录下新建一个 XML 文件,例如:rotate_animation.xml

复制代码
?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"          <!-- 动画持续时间,毫秒 -->
    android:fromDegrees="0"          <!-- 起始角度 -->
    android:toDegrees="360"          <!-- 结束角度 -->
    android:pivotX="50%"             <!-- 旋转中心点 X 坐标 -->
    android:pivotY="50%"             <!-- 旋转中心点 Y 坐标 -->
    android:repeatCount="infinite"   <!-- 重复次数,infinite 表示无限循环 -->
    android:repeatMode="restart"     <!-- 重复模式,restart 表示每次都重新开始 -->
android:interpolator="@android:anim/linear_interpolator" /> <!-- 插值器 -->

2. 在代码中使用动画

复制代码
mageView imageView = findViewById(R.id.imageView);
Animation rotateAnimation = AnimationUtils.loadAnimation(this, R.anim.rotate_animation);
imageView.startAnimation(rotateAnimation);

二、使用代码动态创建动画

复制代码
ImageView imageView = findViewById(R.id.imageView);

RotateAnimation rotateAnimation = new RotateAnimation(
    0f, 360f,                          // 起始角度,结束角度
    Animation.RELATIVE_TO_SELF, 0.5f,  // 旋转中心点 X 坐标
    Animation.RELATIVE_TO_SELF, 0.5f   // 旋转中心点 Y 坐标
);

rotateAnimation.setDuration(1000);     // 动画持续时间
rotateAnimation.setRepeatCount(Animation.INFINITE); // 无限循环
rotateAnimation.setInterpolator(new LinearInterpolator()); // 线性插值器

imageView.startAnimation(rotateAnimation);

三、使用属性动画(更灵活,推荐)

复制代码
ImageView imageView = findViewById(R.id.imageView);

ObjectAnimator rotateAnimator = ObjectAnimator.ofFloat(imageView, "rotation", 0f, 360f);
rotateAnimator.setDuration(1000);
rotateAnimator.setRepeatCount(ValueAnimator.INFINITE);
rotateAnimator.setInterpolator(new LinearInterpolator());
rotateAnimator.start();

四、暂停与恢复动画(属性动画)

复制代码
// 暂停动画
rotateAnimator.pause();

// 恢复动画
rotateAnimator.resume();

五、注意事项与建议:

性能优化:如果动画只是简单的旋转,推荐使用 XML 或属性动画。

重复次数:repeatCount 设置为 Animation.INFINITE 或 ValueAnimator.INFINITE 表示无限循环。

插值器选择

LinearInterpolator:匀速旋转

AccelerateInterpolator:加速旋转

DecelerateInterpolator:减速旋转

AccelerateDecelerateInterpolator:先加速后减速旋转

动画停止

使用 Animation 时调用 animation.cancel();

使用属性动画时调用 animator.cancel()。

平移动画

一、XML 视图动画(传统方式,最简单)

1. 创建动画文件

复制代码
res/anim/translate_left_to_right.xml
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="800"
    android:fromXDelta="-100%"
    android:toXDelta="0%"
    android:fromYDelta="0%"
    android:toYDelta="0%"
android:fillAfter="true" />   <!-- 动画结束后停在终点 -->
fromXDelta / toXDelta:水平方向位移,可用具体数值(dp、px)或百分比(相对自身或父容器)。
fromYDelta / toYDelta:垂直方向位移,同上。
fillAfter="true":动画结束后停留在最终位置(否则控件会闪回起点)

2. 使用动画

复制代码
Animation anim = AnimationUtils.loadAnimation(context, R.anim.translate_left_to_right);
view.startAnimation(anim);

二、代码动态创建视图动画

复制代码
TranslateAnimation anim = new TranslateAnimation(
        Animation.RELATIVE_TO_PARENT, -1.0f,   // fromX
        Animation.RELATIVE_TO_PARENT,  0.0f,   // toX
        Animation.RELATIVE_TO_PARENT,  0.0f,   // fromY
        Animation.RELATIVE_TO_PARENT,  0.0f);  // toY
anim.setDuration(800);
anim.setFillAfter(true);
view.startAnimation(anim);

三、属性动画(ObjectAnimator,API 11+,最推荐)

优势:真正改变 View 的坐标,不会出现视图动画"点击区域还在原地"的问题;

兼容硬件加速,性能更好。

1. 水平位移

复制代码
ObjectAnimator.ofFloat(view, "translationX", -view.getWidth(), 0f)
              .setDuration(800)
              .start();

2. 垂直位移

复制代码
ObjectAnimator.ofFloat(view, "translationY", 0f, 200f)
              .setDuration(800)
              .start();

3. 组合位移(X+Y)

复制代码
Path path = new Path();
path.moveTo(0f, 0f);
path.lineTo(200f, 100f);
ObjectAnimator.ofFloat(view, View.X, View.Y, path)
              .setDuration(800)
              .start();

四、常用扩展技巧

五、视图动画 vs 属性动画(避坑)

缩放动画

XML 视图动画

复制代码
在 res/anim/scale_center.xml
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="400"
    android:fromXScale="1.0"
    android:toXScale="1.5"
    android:fromYScale="1.0"
    android:toYScale="1.5"
    android:pivotX="50%"          <!-- 中心点:水平中点 -->
    android:pivotY="50%"          <!-- 中心点:垂直中点 -->
android:fillAfter="true" />   <!-- 动画结束后保持最终大小 -->

使用:

复制代码
Animation anim = AnimationUtils.loadAnimation(context, R.anim.scale_center);
imageView.startAnimation(anim);

代码动态创建视图动画

复制代码
ScaleAnimation anim = new ScaleAnimation(
        1f, 1.5f,      // 起始/结束 X 缩放
        1f, 1.5f,      // 起始/结束 Y 缩放
        Animation.RELATIVE_TO_SELF, 0.5f,  // 中心点 X
        Animation.RELATIVE_TO_SELF, 0.5f); // 中心点 Y
anim.setDuration(400);
anim.setFillAfter(true);
imageView.startAnimation(anim);

属性动画(ObjectAnimato r

真正改变 View 的 scaleX/scaleY,点击区域同步放大/缩小

复制代码
imageView.setPivotX(imageView.getWidth()  / 2f);   // 中心点
imageView.setPivotY(imageView.getHeight() / 2f);

ObjectAnimator scaleX = ObjectAnimator.ofFloat(imageView, "scaleX", 1f, 1.5f);
ObjectAnimator scaleY = ObjectAnimator.ofFloat(imageView, "scaleY", 1f, 1.5f);

AnimatorSet set = new AnimatorSet();
set.playTogether(scaleX, scaleY);
set.setDuration(400);
set.start();

ViewPropertyAnimator(一行代码链式调用)

复制代码
imageView.animate()
         .scaleX(1.5f)
         .scaleY(1.5f)
         .setDuration(400)
         .start();

常见需求速查表

注意点

视图动画(ScaleAnimation) 只改变绘制大小,点击区域不变

属性动画(ObjectAnimator / View.animate) 会真正改变 View 的大小和触控区域,推荐优先使用

若需兼容 API < 11,可引入 NineOldAndroids(已过时)或保留 XML 视图动画。

淡入淡出

XML 视图动画

在 res/anim/fade_in.xml(淡入)

复制代码
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"
    android:fromAlpha="0.0"
    android:toAlpha="1.0"
android:fillAfter="true" />

res/anim/fade_out.xml(淡出)

复制代码
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"
    android:fromAlpha="1.0"
    android:toAlpha="0.0"
android:fillAfter="true" />

使用:

复制代码
Animation in  = AnimationUtils.loadAnimation(context, R.anim.fade_in);
Animation out = AnimationUtils.loadAnimation(context, R.anim.fade_out);

view.startAnimation(in);   // 淡入
view.startAnimation(out);  // 淡出

代码动态创建视图动画

// 淡入

复制代码
AlphaAnimation fadeIn = new AlphaAnimation(0f, 1f);
fadeIn.setDuration(1000);
fadeIn.setFillAfter(true);
view.startAnimation(fadeIn);

// 淡出

复制代码
AlphaAnimation fadeOut = new AlphaAnimation(1f, 0f);
fadeOut.setDuration(1000);
fadeOut.setFillAfter(true);
view.startAnimation(fadeOut);

属性动画(ObjectAnimator,推荐)

// 淡入

复制代码
ObjectAnimator.ofFloat(view, View.ALPHA, 0f, 1f)
              .setDuration(1000)
              .start();

// 淡出

复制代码
ObjectAnimator.ofFloat(view, View.ALPHA, 1f, 0f)
              .setDuration(1000)
              .start();

ViewPropertyAnimator(一行链式)

复制代码
view.animate()
    .alpha(1f)   // 淡入
    .setDuration(1000)
    .start();

view.animate()
    .alpha(0f)   // 淡出
    .setDuration(1000)
.start();

交叉淡入淡出(两个 View 场景切换)

复制代码
View oldView = findViewById(R.id.old);
View newView = findViewById(R.id.new);

// 先把新 View 设为透明
newView.setAlpha(0f);
newView.setVisibility(View.VISIBLE);

oldView.animate()
       .alpha(0f)
       .setDuration(500)
       .withEndAction(() -> {
           oldView.setVisibility(View.GONE);
           newView.animate()
                  .alpha(1f)
                  .setDuration(500)
                  .start();
       })
       .start();

常见需求速查表

视图动画(AlphaAnimation) 只改变绘制透明度,不触发 setVisibility() 事件;如需隐藏,记得手动 setVisibility(GONE)。

属性动画(ObjectAnimator / View.animate) 会真正修改 View.ALPHA,可配合 setVisibility() 实现更复杂的场景切换。

交叉淡入淡出时,两个 View 必须位于同一个父布局,且新 View 初始 visibility = VISIBLE + alpha = 0。

动画插值器

LinearInterpolator 匀速 旋转加载圈

AccelerateInterpolator 越来越快 页面滑出

DecelerateInterpolator 越来越慢 页面滑入

AccelerateDecelerateInterpolator 两头慢中间快 默认效果

AnticipateInterpolator 先回拉再前进 弹出菜单

OvershootInterpolator 冲过头再回弹 点赞放大

AnticipateOvershootInterpolator 回拉 + 冲过头 卡片翻转

BounceInterpolator 落地弹跳 掉落按钮

CycleInterpolator(float cycles) 正弦循环 抖动提示

FastOutSlowInInterpolator Material 默认 所有 Material 动效

LinearOutSlowInInterpolator 先快后慢 Snackbar 滑出

FastOutLinearInInterpolator 先慢后快 返回按钮

设置插值器

setInterpolator

android:interpolator="@android:anim/accelerate_decelerate_interpolator"

AnimationListener视图动画

AnimationListener 是 视图动画(View Animation) 专用的回调接口,用来监听 Animation 的生命周期事件

当使用 AlphaAnimation、ScaleAnimation、TranslateAnimation、RotateAnimation、AnimationSet 等旧版补间动画时,通过它可以在动画开始、结束、重复时执行额外逻辑。

复制代码
Animation anim = AnimationUtils.loadAnimation(context, R.anim.fade_in);

anim.setAnimationListener(new Animation.AnimationListener() {
    @Override
    public void onAnimationStart(Animation animation) {
        Log.d("TAG", "动画开始");
    }

    @Override
    public void onAnimationEnd(Animation animation) {
        Log.d("TAG", "动画结束");
        view.setVisibility(View.GONE); // 常见操作
    }

    @Override
    public void onAnimationRepeat(Animation animation) {
        Log.d("TAG", "动画重复");
    }
});

view.startAnimation(anim);

AnimatorListener属性动画

Android 属性动画(ObjectAnimator、ValueAnimator、AnimatorSet 等)的监听器接口叫 AnimatorListener ,位于

包 android.animation.Animator.AnimatorListener。它与"视图动画"的 AnimationListener 不同,后者只适用于旧版补间动画。

  1. 接口方法一览

AnimatorUpdateListener属性动画

Android 属性动画体系里,AnimatorUpdateListenerValueAnimator (包括其子类 ObjectAnimator、AnimatorSet)提供的"帧级"回调接口。

它会在每一帧刷新时调用一次,让你拿到「当前这一帧算出来的值」并手动刷新 UI,是自定义动画的核心手段。

复制代码
ValueAnimator valueAnim = ValueAnimator.ofFloat(0f, 100f);  // 值区间
valueAnim.setDuration(1000);

valueAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        // 1. 取出当前帧值
        float curValue = (float) animation.getAnimatedValue();
        // 2. 手动赋给任意属性
        textView.setTranslationX(curValue);
        // 3. 如需要,可刷新自定义 View
        // invalidate();
    }
});

valueAnim.start();

Android 动画类型

一、视图动画(View Animation,API 1+)

子类:Tween Animation(补间动画)和 Frame Animation(逐帧动画)。

特点:只改绘制矩阵,不改真实属性;点击区域不跟随;兼容所有版本。

典型使用:AlphaAnimation、ScaleAnimation、TranslateAnimation、RotateAnimation、AnimationDrawable。

二、属性动画(Property Animation,API 11+)

核心类:ValueAnimator、ObjectAnimator、AnimatorSet。

特点:真正改变对象属性值;支持可暂停、可逆、可插值;点击区域同步。

兼容低版本:NineOldAndroids(已弃用),或使用 AndroidX Core 的 ViewCompat.animate()。

三、转场动画(Transition Framework,API 19+)

包路径:android.transition.*

适用场景:Activity/Fragment 切换、布局内容变化(如列表→详情)。

核心 API:

· Explode、Slide、Fade

· TransitionManager.beginDelayedTransition()

共享元素:ActivityOptions.makeSceneTransitionAnimation()

特点:自动捕捉起始/结束状态并执行补间;与属性动画底层打通。

四、矢量动画(Animated Vector Drawable / Vector Animation,API 21+)

文件格式:res/drawable/animated_vector.xml

使用:

静态矢量图 vector

动画指令 objectAnimator 嵌入到 <target> 节点

场景:图标动效、加载动画、路径变形(path morphing)

兼容:使用 AnimatedVectorDrawableCompat(API 14+)

五、物理动画(Physics-based Animation,API 16+)

框架 androidx.dynamicanimation:dynamicanimation

子类:

SpringAnimation(弹簧)

FlingAnimation(甩动/惯性滑动)

特点:基于物理模型(阻尼、刚度、摩擦),真实自然;无需指定时长和终止值。

相关推荐
严同学正在努力3 分钟前
从备份到恢复:我用 30 分钟恢复了误删的核心业务表
android·java·数据库·ai
梦想三三30 分钟前
LangChain Output Parser 实战:从字符串到结构化数据的完整指南
android·服务器·langchain·github·uv
爱笑鱼3 小时前
Binder(八):远端进程死了,BinderProxy 为什么还能收到通知?
android
Android-Flutter3 小时前
Kotlin 冷流与热流详解
android·kotlin
zhangphil3 小时前
Android ContentProvider/ContentResolver读图片,跨进程 IPC慢
android
yueqc14 小时前
Android .so 文件压缩
android·so·包体积
龚礼鹏4 小时前
深入解析 Android Automotive (AAOS) 启动流程与 CarService 核心机制(基于 Android 16 最新源码视角)
android
rosmis4 小时前
agent各指标定义
android·java·开发语言
风样滴男人哟5 小时前
PHP特性之反射类ReflectionClass机制
android·开发语言·php
小孔龙6 小时前
RenderNode 与 DisplayList:Android 硬件加速的绘制记录与复用
android·性能优化