从 Android 12 开始,SplashScreen
API 允许应用以动画方式启动,包括启动时的应用内动画、显示应用图标的启动画面以及到应用本身的过渡。SplashScreen
是一个 Window
,因此它覆盖了 Activity
。
启动画面体验为每个应用启动提供了标准的设计元素,但它也是可自定义的,因此您的应用可以保持其独特的品牌。
除了使用 SplashScreen
平台 API 之外,您还可以使用 SplashScreen
兼容库,该库包装了 SplashScreen
API。
启动画面的工作原理
当用户启动应用时,应用进程未运行(冷启动)或 Activity
未创建(温启动),则会发生以下事件
系统使用您定义的主题和任何动画显示启动画面。
应用准备就绪后,启动画面将被关闭,应用显示。
在 热启动 期间,启动画面永远不会显示。
启动画面的元素和机制
启动画面的元素由 Android 清单文件中的 XML 资源文件定义。每个元素都有亮模式和暗模式版本。
启动画面的可自定义元素包括应用图标、图标背景和窗口背景
请考虑图 2 中显示的以下元素
1 应用图标必须是矢量可绘制对象。它可以是静态的或动画的。尽管动画可以无限期持续,但我们建议不要超过 1000 毫秒。启动器图标是默认图标。
2 图标背景是可选的,如果您需要在图标和窗口背景之间有更多对比度,则它很有用。如果您使用 自适应图标,则如果与窗口背景有足够的对比度,则会显示其背景。
3 与自适应图标一样,前景的三分之一被遮罩。
4 窗口背景由单一不透明颜色组成。如果设置了窗口背景并且是纯色,则在未设置属性时默认使用它。
启动画面尺寸
启动画面图标使用与 自适应图标 相同的规范,如下所示
- 品牌图像:这必须是 200×80 dp。
- 带有图标背景的应用图标:这必须是 240×240 dp,并适合直径为 160 dp 的圆圈内。
- 没有图标背景的应用图标:这必须是 288×288 dp,并适合直径为 192 dp 的圆圈内。
例如,如果图像的完整尺寸为 300×300 dp,则图标需要适合直径为 200 dp 的圆圈内。圆圈外的所有内容都将变为不可见(遮罩)。
启动画面动画和启动序列
冷启动时启动应用通常会带来额外的延迟。向启动画面添加动画图标具有明显的审美吸引力,并提供更优质的体验。用户研究表明,观看动画时,感知的启动时间更短。
启动画面动画嵌入在启动序列组件中,如图 4 所示。
进入动画:这包括系统视图到启动画面。它由系统控制,不可自定义。
启动画面(在序列的“等待”部分显示):启动画面可以自定义,允许您提供自己的徽标动画和品牌。它必须满足此页面中描述的 要求 才能正常工作。
退出动画:这包括隐藏启动画面的动画。如果要 自定义它,请使用
SplashScreenView
及其图标。您可以在其上运行任何动画,并设置转换、不透明度和颜色的设置。在这种情况下,在动画完成后手动删除启动画面。
在运行图标动画时,应用启动让您可以选择在应用更早准备就绪的情况下跳过序列。应用触发 onResume()
或启动画面自动超时,因此请确保可以舒适地跳过该动画。仅当应用在视觉上稳定时,才应使用 onResume()
关闭启动画面,因此不需要额外的微调器。引入不完整的界面可能会让用户感到震惊,并可能给人留下不可预测或缺乏完善的印象。
启动画面动画要求
您的启动画面必须符合以下规范
设置单一窗口背景颜色,不透明。日间和夜间模式受
SplashScreen
兼容库 支持。确保动画图标符合以下规范
- 格式:图标必须是 动画矢量可绘制对象 (AVD) XML。
- 尺寸:AVD 图标必须是自适应图标的四倍大小,如下所示
- 图标区域必须为 432 dp,换句话说,是未遮罩的自适应图标 108 dp 区域的四倍。
- 图像的内三分之二在启动器图标上可见,必须为 288 dp,换句话说,是构成自适应图标内部遮罩区域的 72 dp 的四倍。
- 持续时间:我们建议在手机上不要超过 1000 毫秒。您可以使用延迟启动,但这不能超过 166 毫秒。如果应用启动时间超过 1000 毫秒,请考虑使用循环动画。
确定关闭启动画面的合适时间,这将在您的应用绘制其第一帧时发生。您可以根据关于 将启动画面保留在屏幕上更长时间 部分的描述进一步自定义此操作。
启动画面资源
下载 示例入门套件,该套件演示了如何创建、格式化并将动画导出到 AVD。它包括以下内容
- 动画的 Adobe After Effects 项目文件。
- 最终导出的 AVD XML 文件。
- 动画示例 GIF。
下载这些文件即表示您同意Google 服务条款。
Google 隐私政策描述了此服务中如何处理数据。
自定义应用中的启动画面
默认情况下,如果 windowBackground
为单色,则 SplashScreen
使用主题的 windowBackground
。要自定义启动画面,请向应用主题添加属性。
您可以通过以下任何一种方式自定义应用的启动画面
设置主题属性以更改其外观。
使其在屏幕上显示更长时间。
自定义关闭启动画面的动画。
开始使用
核心 SplashScreen
库将 Android 12 启动画面引入从 API 23 起的所有设备。要将其添加到您的项目中,请将以下代码段添加到您的 build.gradle
文件中
Groovy
dependencies { implementation "androidx.core:core-splashscreen:1.0.0" }
Kotlin
dependencies { implementation("androidx.core:core-splashscreen:1.0.0") }
设置启动画面的主题以更改其外观
您可以在 Activity
主题中指定以下属性来自定义应用的启动画面。如果您已经拥有使用 android:windowBackground
等属性的传统启动画面实现,请考虑为 Android 12 及更高版本提供备用资源文件。
使用
windowSplashScreenBackground
以特定单色填充背景<item name="android:windowSplashScreenBackground">@color/...</item>
使用
windowSplashScreenAnimatedIcon
替换启动窗口中心的图标。仅适用于以 Android 12(API 级别 32)为目标的应用,请执行以下操作
如果对象可以通过
AnimationDrawable
和AnimatedVectorDrawable
进行动画处理和绘制,请设置windowSplashScreenAnimationDuration
以在显示启动窗口时播放动画。对于 Android 13,这并非必需,因为持续时间是从AnimatedVectorDrawable
中直接推断出来的。<item name="android:windowSplashScreenAnimatedIcon">@drawable/...</item>
使用
windowSplashScreenAnimationDuration
指示启动画面图标动画的持续时间。设置此属性不会对启动画面实际显示的时间产生任何影响,但您可以在使用SplashScreenView.getIconAnimationDuration
自定义启动画面退出动画时检索它。有关更多详细信息,请参阅以下关于使启动画面在屏幕上显示更长时间的部分。<item name="android:windowSplashScreenAnimationDuration">1000</item>
使用
windowSplashScreenIconBackgroundColor
设置启动画面图标后面的背景。如果窗口背景和图标之间对比度不够,这将很有用。<item name="android:windowSplashScreenIconBackgroundColor">@color/...</item>
您可以使用
windowSplashScreenBrandingImage
设置要在启动画面底部显示的图像。但是,设计指南建议不要使用品牌图像。<item name="android:windowSplashScreenBrandingImage">@drawable/...</item>
您可以使用
windowSplashScreenBehavior
指定您的应用是否始终在 Android 13 及更高版本中显示启动画面上的图标。默认值为 0,如果启动 Activity 将splashScreenStyle
设置为SPLASH_SCREEN_STYLE_ICON
或遵循启动 Activity 未指定样式的系统行为,则会在启动画面上显示图标。如果您希望永远不会显示空启动画面,并且始终希望显示动画图标,请将其设置为值icon_preferred
。<item name="android:windowSplashScreenBehavior">icon_preferred</item>
使启动画面在屏幕上显示更长时间
您的应用绘制第一个帧后,启动画面就会消失。如果您需要加载少量数据(例如,异步从本地磁盘加载应用内设置),则可以使用 ViewTreeObserver.OnPreDrawListener
暂停应用绘制其第一个帧。
如果您的启动 Activity 在绘制之前完成(例如,通过在 onResume
之前不设置内容视图并完成),则不需要预绘制侦听器。
Kotlin
// Create a new event for the activity. override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // Set the layout for the content view. setContentView(R.layout.main_activity) // Set up an OnPreDrawListener to the root view. val content: View = findViewById(android.R.id.content) content.viewTreeObserver.addOnPreDrawListener( object : ViewTreeObserver.OnPreDrawListener { override fun onPreDraw(): Boolean { // Check whether the initial data is ready. return if (viewModel.isReady) { // The content is ready. Start drawing. content.viewTreeObserver.removeOnPreDrawListener(this) true } else { // The content isn't ready. Suspend. false } } } ) }
Java
// Create a new event for the activity. @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Set the layout for the content view. setContentView(R.layout.main_activity); // Set up an OnPreDrawListener to the root view. final View content = findViewById(android.R.id.content); content.getViewTreeObserver().addOnPreDrawListener( new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { // Check whether the initial data is ready. if (mViewModel.isReady()) { // The content is ready. Start drawing. content.getViewTreeObserver().removeOnPreDrawListener(this); return true; } else { // The content isn't ready. Suspend. return false; } } }); }
自定义关闭启动画面的动画
您可以通过 Activity.getSplashScreen()
进一步自定义启动画面的动画。
Kotlin
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // ... // Add a callback that's called when the splash screen is animating to the // app content. splashScreen.setOnExitAnimationListener { splashScreenView -> // Create your custom animation. val slideUp = ObjectAnimator.ofFloat( splashScreenView, View.TRANSLATION_Y, 0f, -splashScreenView.height.toFloat() ) slideUp.interpolator = AnticipateInterpolator() slideUp.duration = 200L // Call SplashScreenView.remove at the end of your custom animation. slideUp.doOnEnd { splashScreenView.remove() } // Run your animation. slideUp.start() } }
Java
@Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); // ... // Add a callback that's called when the splash screen is animating to the // app content. getSplashScreen().setOnExitAnimationListener(splashScreenView -> { final ObjectAnimator slideUp = ObjectAnimator.ofFloat( splashScreenView, View.TRANSLATION_Y, 0f, -splashScreenView.getHeight() ); slideUp.setInterpolator(new AnticipateInterpolator()); slideUp.setDuration(200L); // Call SplashScreenView.remove at the end of your custom animation. slideUp.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { splashScreenView.remove(); } }); // Run your animation. slideUp.start(); }); }
在此回调开始时,启动画面上的 动画矢量可绘制对象 开始。根据应用启动的持续时间,可绘制对象可能处于动画的中间状态。使用 SplashScreenView.getIconAnimationStart
了解动画何时开始。您可以按如下方式计算图标动画的剩余持续时间
Kotlin
// Get the duration of the animated vector drawable. val animationDuration = splashScreenView.iconAnimationDuration // Get the start time of the animation. val animationStart = splashScreenView.iconAnimationStart // Calculate the remaining duration of the animation. val remainingDuration = if (animationDuration != null && animationStart != null) { (animationDuration - Duration.between(animationStart, Instant.now())) .toMillis() .coerceAtLeast(0L) } else { 0L }
Java
// Get the duration of the animated vector drawable. Duration animationDuration = splashScreenView.getIconAnimationDuration(); // Get the start time of the animation. Instant animationStart = splashScreenView.getIconAnimationStart(); // Calculate the remaining duration of the animation. long remainingDuration; if (animationDuration != null && animationStart != null) { remainingDuration = animationDuration.minus( Duration.between(animationStart, Instant.now()) ).toMillis(); remainingDuration = Math.max(remainingDuration, 0L); } else { remainingDuration = 0L; }
其他资源
- 将您现有的启动画面实现迁移到 Android 12 及更高版本
- Now in Android 应用,其中显示了启动画面的真实世界实现