You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在Android中实现应用启动与退出时的智能图标动画?

嘿,这个问题问到点子上了!MIUI 9那灵动的智能图标动画确实圈粉不少,要在Android系统里实现类似的应用启动/退出图标动画效果,咱们可以从「系统启动器(Launcher)定制」和「应用自身配合」两个核心方向来搞,我给你拆解具体步骤和代码示例:

一、核心原理先理清楚

这种动画的本质是在应用启动/退出的关键生命周期节点,给桌面图标触发对应的过渡动画——要么是Launcher主动感知应用状态变化来播放动画,要么是应用自身和Launcher配合,做前后衔接的动画效果。

二、系统/Launcher层面的完整实现(像MIUI那样)

这是MIUI实现的核心方式,因为定制系统的Launcher可以直接控制图标显示和应用状态监听:

步骤1:监听应用的启动与退出事件

Launcher需要精准捕捉两个关键时机:

  • 用户点击图标启动应用时:Launcher自身发起启动应用的请求,这时可以先播放图标动画,再启动应用。
  • 应用退出回到桌面时:通过ActivityManagerUsageStatsManager监听应用的后台状态,当检测到目标应用回到后台时,触发图标退出动画。

步骤2:为图标准备动画资源

针对每个支持的应用,准备对应的动画序列——可以用帧动画(AnimationDrawable)或者属性动画(ValueAnimator):

  • 启动动画:比如图标缩放、渐变、小范围位移,模拟“激活”的效果。
  • 退出动画:比如从动态状态过渡回静态图标,或者做一个收缩的动画。

步骤3:自定义图标View集成动画逻辑

写一个继承自ImageView的自定义View,把动画逻辑封装进去:

class AnimatedAppIconView(context: Context, attrs: AttributeSet) : ImageView(context, attrs) {
    // 启动动画:缩放+回弹效果
    private val launchAnimator = ValueAnimator.ofFloat(1f, 1.25f, 1f).apply {
        duration = 350
        interpolator = OvershootInterpolator()
        addUpdateListener { anim ->
            val scale = anim.animatedValue as Float
            scaleX = scale
            scaleY = scale
        }
    }

    // 退出动画:帧动画过渡回静态图标
    private val exitAnimDrawable = AnimationDrawable().apply {
        addFrame(context.getDrawable(R.drawable.icon_exit_frame1)!!, 60)
        addFrame(context.getDrawable(R.drawable.icon_exit_frame2)!!, 60)
        addFrame(context.getDrawable(R.drawable.app_icon_static)!!, 60)
        isOneShot = true
    }

    fun playLaunchAnimation() {
        if (!launchAnimator.isRunning) {
            launchAnimator.start()
        }
    }

    fun playExitAnimation() {
        setImageDrawable(exitAnimDrawable)
        exitAnimDrawable.start()
    }
}

步骤4:在Launcher中关联动画与应用状态

当用户点击图标时,先播放动画再启动应用:

iconView.playLaunchAnimation()
// 延迟150ms让动画先展示一部分,提升感知
Handler(Looper.getMainLooper()).postDelayed({
    context.startActivity(intent)
}, 150)

监听应用退出时,可以通过ActivityManager获取运行中的进程,判断目标应用是否回到后台,然后触发退出动画:

private fun checkAppExit(packageName: String) {
    val am = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
    val runningApps = am.runningAppProcesses
    val isAppInForeground = runningApps.any { it.processName == packageName && it.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND }
    if (!isAppInForeground) {
        // 找到对应图标View,播放退出动画
        findIconViewByPackage(packageName)?.playExitAnimation()
    }
}
三、应用自身的轻量实现(无需定制Launcher)

如果不想依赖系统Launcher的定制,应用可以在启动/退出时,通过界面内的动画和图标做衔接:

启动时:Splash页配合动画

在Splash Activity中,放一个和应用图标一致的View,播放启动动画后再进入主界面:

// SplashActivity.java
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_splash);

    ImageView splashIcon = findViewById(R.id.splash_icon);
    Animation launchAnim = AnimationUtils.loadAnimation(this, R.anim.icon_launch_anim);
    splashIcon.startAnimation(launchAnim);

    launchAnim.setAnimationListener(new Animation.AnimationListener() {
        @Override
        public void onAnimationStart(Animation animation) {}

        @Override
        public void onAnimationEnd(Animation animation) {
            startActivity(new Intent(SplashActivity.this, MainActivity.class));
            finish();
            // 关闭Splash时的过渡动画,让图标动画更连贯
            overridePendingTransition(0, 0);
        }

        @Override
        public void onAnimationRepeat(Animation animation) {}
    });
}

退出时:主界面播放退出动画再finish

在主Activity的返回逻辑中,先播放图标相关的动画,再退出应用:

@Override
public void onBackPressed() {
    ImageView appIcon = findViewById(R.id.main_app_icon); // 界面上的图标元素
    Animation exitAnim = AnimationUtils.loadAnimation(this, R.anim.icon_exit_anim);
    appIcon.startAnimation(exitAnim);

    exitAnim.setAnimationListener(new Animation.AnimationListener() {
        @Override
        public void onAnimationStart(Animation animation) {}

        @Override
        public void onAnimationEnd(Animation animation) {
            MainActivity.super.onBackPressed();
            overridePendingTransition(0, 0);
        }

        @Override
        public void onAnimationRepeat(Animation animation) {}
    });
}
四、关键注意事项
  • 性能优先:动画要简洁,尽量用硬件加速的属性动画,避免复杂帧动画导致掉帧。
  • 兼容性适配:不同Android版本的API(比如UsageStatsManager需要API21+)和Launcher行为差异,要做好适配。
  • 资源适配:为不同分辨率屏幕准备多套动画资源,避免拉伸模糊。

内容的提问来源于stack exchange,提问作者Sagar Jethva

火山引擎 最新活动