可能有不少小伙伴已经留意到 Android 12
上推出了全新的启动画面 APISplashScreen
。同时为了兼容低版本的使用,Jetpack
框架里推出了同名库。
本次针对这个库的使用和原理做个全面的介绍,将按照如下几个方面去展开:
- 首先简单探讨一下为什么需要启动画面
- 接着一起回顾一下之前打造启动画面的常规做法
- 然后重点阐述一下 SplashScreen 库的目的,以及如何使用
- 最后介绍一下 SplashScreen 库大致的实现原理
1. 为什么需要启动画面
1.1 启动画面的作用
- 当我们打开各种桌面软件或移动端 App 的时候,首先会看到的经常是一段过渡画面。用以展示产品所属的公司、品牌的图标、公司的 Slogan 等,借以宣传公司的调性和传达一些特色
- 同时在节日庆典、特殊活动的时候展示广告页面或活动海报
- 在启动画面展示的同时,背后的内容得以加载
同时在一定程度上缓解用户的等待,启动画面良好设计的话,还能使得这个枯燥的过程显得有趣和充满期待!
1.2 App 启动的典型流程
来看一下 App 启动的典型流程。
点击 Launcher 上的 Logo 之后,首先用户将看到一个启动画面,如果是初次启动的话接着会展示 Guide 画面引导用户了解如何使用;如果是节日或广告需要的话展示的是广告宣传画面,最后才是展示内容的主画面。
我们本次探讨的核心就是第一个启动画面。
Jetpack SplashScreen 库正是用来打造用户看到的第一个启动画面,在讲述之前,先来回顾一下之前的常规做法。
2. 常规做法
我们知道从点击 Launcher 上的 icon 到 App 内容描画之前,有很多准备工作。在这段时间是看不到目标 App 内容的。
为了快速响应用户的点击或缓解用户的等待,在 App 描画之前系统将启动专用的 SplashScreenWindow 盖在 App 之上。该Window 的呈现源自于 App 主题方面的配置。
配置的不同进而影响到启动 Window 的表现,我们来看看各种配置的做法。
2.1 默认的启动画面背景
假使 App 的主题针对 Window 背景什么都不设置,你会发现启动的过程中总有个默认的白画面一闪而过。
<style name="SplashThemeBase.DefaultBg"/>
2.2 不设置启动画面背景
当然可以将 windowBackground
设置为空,可是你会发现启动的过程中又变成黑色一片闪过。
<style name="SplashThemeBase.NoBg"> <item name="android:windowBackground">@null</item> </style>
无论是白画面还是黑画面一闪而过,都无法接受,所以还得继续优化。
2.3 直接关闭启动画面
无论白画面还是黑画面一闪而过的体验都不好,这时候可能会想到关闭默认的启动画面。通过 windowDisablePreview
属性可以彻底关闭启动画面。
<style name="SplashThemeBase.TransparentBg"> <item name="android:windowDisablePreview">true</item> </style>
这样一来,确实看不到启动画面的存在了,但整个过程貌似“变慢”了。实际上性能并没有**“劣化”**,只是启动中过渡的 Window 不存在了。假使 Application 或 Activity 等组件里存在耗时逻辑的话,这种劣化会更加明显。
相较于前面的黑白画面一闪而过,这种变慢的体验也好不到哪去。
2.4 设置启动画面背景
绕来绕去,最后我们发现还是得提供一个恰当的启动画面。具体在于将 UI 提供的背景色、Icon、Brand 等资源组合成一个 LayerListDrawable
,然后将其设置到 windowBackground 中即可。
<!--theme--> <style name="SplashThemeBase.WithBg"> <item name="android:windowBackground">@drawable/ic_splash_bg</item> </style> <!--drawable--> <layer-list ... > <item android:drawable="@drawable/ic_logo"></item> <item android:drawable="@drawable/ic_brand"></item> </layer-list>
这种做法既可以提供体验良好的过渡画面,同时可以快速响应用户的点击。可以说是最为简单也最为便捷的一种实现方式。
2.5 设置启动画面内容
Android 8 加入一个配置启动画面的属性 windowSplashscreenContent,用于配置启动画面的内容。它的优先级高于 windowBackground。两者一起设置的话呢,会覆盖在 windowBackground 上。大体的效果呢和前面的差不多,不再赘述。
<style name="SplashThemeBase.WithBg.SplashScreenContent"> <item name="android:windowSplashscreenContent">@drawable/ic_splash_content</item> </style>
注意:这个属性自 Android 8 加入,从 12 开始废弃
2.6 定义启动专用 Activity
有的时候觉得单单设置一张背景图太过简单,无法实现一些复杂的启动效果。又或者希望能和广告或节日的画面深度配合起来。这时候难免需要定义一个专门的启动 Activity。
具体来讲需要在入口 Activity 前预设专门的 Splash Activity来显示启动画面,Splash Activity 在一定时间后自动跳转到入口 Activity
启动 Activity 提供类似启动画面的布局。
<androidx.constraintlayout.widget.ConstraintLayout ... > <ImageView android:src="@drawable/ic_icon" ... /> <ImageView android:src="@drawable/ic_brand" ... /> </androidx.constraintlayout.widget.ConstraintLayout>
在画面展示后配合定时跳转等逻辑去打开广告或海报等画面。
class SplashActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { ... setContentView(binding.root) goToMainScreenDelayed() } }
因为有了自己实现的启动 Activity,所以系统提供的启动画面可以关闭。当然也可以将系统的启动画面的 windowBackground 设置为整体背景色相接近的色调。
<style name="SplashThemeBase.NoSplashWindow" > <item name="android:windowDisablePreview">true</item> </style>
上面是通过 Activity 方式打造的启动画面的效果。
DEMO 的效果和前面的主题方式的效果差不多,但是这种做法将会拥有更大的定制空间。比如可以接入跨平台的 Lottie
动画库,打造更为丰富、炫酷、平台统一的启动效果!
3. Jetpack SplashScreen 的目的和使用
可以看到之前提供的主题配置方式只能展示一张背景图,这种静态效果看久了着实单调。而且这张图还需要我们自行组合 App 的 Icon、Brand 的 Logo,这就需要考虑很多 Size、位置、屏幕适配等 UI 细节,不太方便。如果需要丰富、灵活一些的效果,又需要自定义专用的 Activity 来解决,这样一来又显得繁琐。
正因为此,Jetpack 上推出了 SplashScreen 库,来高效、灵活地重塑启动画面。而 SplashScreen 库基于 Android 12 的新特性 SplashScreen API,所以我们先来了解一下这个特性。
3.1 Android 12 SplashScreen
3.1.1 特性介绍
Android 12 上 App 启动的时候将先展示一个启动画面的进场部分,该部分的呈现由 SplashScreen API 提供的更为丰富的属性来定制。之后在App 描画第一帧的时候将该画面的视图回调给我们来定制退场部分的效果。
进场和退场两部分共同组成了全新的 SplashScreen API。
需要说明的是,不同于之前的版本,12 上什么即便都不配置,启动画面会是白色背景下展示 Adaptive Icon
的一个效果。这相较于之前的纯白背景要好了不少。
3.1.2 画面构成
SplashScreen 的画面由一个 SplashScreenWindow 承载,中间是一个 AdaptiveIcon,SplashScreen API 则提供了丰富的属性来指定该的各部分构成,简洁明了。比如:
windowSplashScreenAnimatedIcon:指定 App Icon 的图片,如果指定的是 Animated Vector Drawable 的话,在启动画面展示的同时会执行一个 Icon 动画效果
windowSplashScreenIconBackgroundColor:Icon 背景色
Adaptive Icon Mask:由 Launcher 的配置指定,主题无法更改,说明一下
windowSplashScreenBackground:Window 背景色,和之前的 windowBackground 属性类似
windowSplashScreenBrandingImage:放置品牌 Logo
当 SplashScreenWindow 退场的时候整个画面的视图会被封装到 SplashScreenView 中供我们实现退场效果。
下面这是 Gmail 适配了 SplashScreen API 后的启动效果。简单来讲就是一个进场的 M 字母的 Path动画,退场的时候直接结束到目标内容的效果。
并没有适配 Icon 背景、Brand Logo、退场动画等特性,后面的章节将充分演示各项特性。
3.1.3 启动规则
在冷启动和暖启动的时候展示 SplashScreen,热启动的时候从不展示该画面。
冷启动:进程尚不存在的情况下点击 App Icon 的启动
暖启动:进程存在但 App 不在前台,并且 Activity 已经销毁了的启动
热启动:进程存在但 App 不在前台,并且 Activity 尚未销毁的启动
3.2 Jetpack SplashScreen
3.2.1 目的
Android 12 的 SplashScreen API 非常好用,但是低版本无法尝鲜,所以 Jetpack 里推出了同名库。
它是为了兼容 12 之前低版本的 UI 库,最早兼容到 Android 6(API 23),6.0 及以上的设备占用率近 9 成,完全够用了。它通过整合和统一 SplashScreen API,达到一套代码实现近乎一致的 App 启动体验。
简述:
兼容低版本系统的启动画面 UI 库
支持到 Android 6.0(近 9 成)
整合 12 的 SplashScreen API
一套代码打造近乎一致的启动效果
3.2.2 提供的主题和属性
SplashScreen 库的版本到了 1.0.0-alpha01
版,在 gradle
文件里简单导入即可。
dependencies { implementation "androidx.core:core-splashscreen:1.0.0-alpha01" }
它预设了主题供我们使用,必须将入口 Activity
的主题改成扩展自这个主题。
<style name="Theme.SplashScreen" parent="Theme.SplashScreenBase"> <item name="windowSplashScreenAnimatedIcon">@android:drawable/sym_def_app_icon</item> ... </style>
同时预设了些属性供我们覆写和提供自己的启动画面资源。
<attr format="reference" name="postSplashScreenTheme"/> <attr format="reference" name="windowSplashScreenAnimatedIcon"/> <attr format="integer" name="windowSplashScreenAnimationDuration"/> <attr format="color" name="windowSplashScreenBackground"/>
这里需要提醒两点:
- SplashScreen 库针对 12 之前的低版本暂不支持设置 Icon Bg,和 Brand Icon 的属性
postSplashScreenTheme
属性用来指定 Activity 最终的主题,避免使用预设的主题影响目标 Actvitiy 的主题展示
3.2.3 提供的 API
SplashScreen 库还提供了逻辑方面的 API,供我们去实现启动画面时长的控制,启动画面退场效果的实现需求。