TL;DR
- 导入
implementation 'androidx.core:core-splashscreen:1.0.1'
- 继承主题
Theme.ScreenSplash
,继承的主题可以设置前景和背景以及时间(最大500),类似icon - 使用主题
在国产大厂的APP上,每一个Feature,每一个模块,每一个按钮,甚至每一个不可交互的地方,它都有出生的意义:广告位。
闪屏页的战略地位不言而喻😄
在 Android 12(SDK 31)之前,应用的启动画面(Splash Screen)一直是个令人头疼的问题。开发者们不得不绞尽脑汁,通过自定义 Activity 主题、设置 windowBackground
或者创建一个独立的 Splash Activity 来模拟启动效果。
不仅需要作为天然的广告位,这个一闪而过页面承载太多东西了。你的所有需要注册的内容,所有内容的完整性检查,服务器判断,DNS解析。当然还有广告的加载以及用户的手有没有抖动…
虽然目前看来体验不尽人意,适配寥寥无几,不过当初Android12似乎真的想改变这些(当然不止这些,更多的可能是体验统一的问题),所以带来一个原生,更高效的解决方案。抛开这些开发决定不了的内容,下面我简单记录一下自己适配这个SplashScreen,当然这也是我第一次使用这个特性。
核心概念与 Theme.SplashScreen
属性详解
Android 12 的启动画面不再是应用自身绘制的 View,而是由系统根据主题配置生成并管理。你的启动 Activity 会首先应用一个继承自 Theme.SplashScreen
的主题,系统会根据该主题的属性来渲染启动画面,并在应用准备就绪后平滑过渡到应用真正的界面。下面是我在网上找到的VerseAPP的动画闪屏页(你也可以下载查看teelgram的动画效果):

以下是 Theme.SplashScreen
主题及其关键属性的详细解析:
1. 父主题:Theme.SplashScreen
- 作用: 这是 Android 12+ 系统提供的启动画面基础主题。你的自定义启动主题必须继承这个主题,才能享受到系统级别的启动画面管理和动画效果。
2. 背景属性:windowSplashScreenBackground
类型: Drawable 引用(@drawable/
或 @color/
)
作用: 定义启动画面的背景。这是替换传统“白屏”的关键。
自定义方案:
- 纯色: 最简单也是最高效的方式,直接引用一个颜色资源,如
<item name="windowSplashScreenBackground">@color/your_brand_color</item>
。 - 渐变色: 创建一个
shape
Drawable,并在其中定义gradient
标签,实现平滑的颜色过渡。 - 图片作为背景(慎用,推荐 LayerList): 虽然可以直接引用一张图片 (
@drawable/your_image
),但通常不推荐直接将一张大图作为背景,因为它可能导致屏幕适配问题、文件尺寸增大和内存开销。 - LayerList 组合背景
3. 图标属性:windowSplashScreenAnimatedIcon
- 类型: Drawable 引用(
@drawable/
或@mipmap/
) - 作用: 定义在启动画面中心显示的图标或动画。
- 可选动画类型:
- Animated Vector Drawable (AVD):
- 格式: XML (
.xml
),定义了矢量图的动画。 - 优点: 官方推荐,文件小巧,可缩放不失真,性能优秀,可以实现复杂的矢量动画。
- 创建: 复杂动画通常需要手动编写 XML 或借助工具。
- 格式: XML (
- Animation Drawable:
- 格式: XML (
.xml
),引用一系列帧图片。 - 优点: 简单易懂,适合简单的帧动画。
- 缺点: 每一帧都是一张图片,文件体积大,内存占用高,缩放可能失真。适用于帧数非常少且简单的动画。
- 格式: XML (
- 自适应图标 (Adaptive Icon):
- 格式: 通常是矢量图,由前景层 (
@mipmap/ic_launcher_foreground
) 和背景层 (@mipmap/ic_launcher_background
) 组成。 - 优点: 系统原生支持,自动适应不同形状的图标蒙版,无需额外动画即可平滑缩放。
- 最常用方案: 如果没有自定义动画需求,直接使用你的自适应图标前景层即可,例如:
<item name="windowSplashScreenAnimatedIcon">@mipmap/ic_launcher_foreground</item>
。
- 格式: 通常是矢量图,由前景层 (
- Animated Vector Drawable (AVD):
4. 动画持续时间:windowSplashScreenAnimationDuration
- 类型: 整数(毫秒)
- 作用: 定义
windowSplashScreenAnimatedIcon
中图标动画的持续时间。系统会在这个时间结束后开始淡出启动画面。 - 注意: 你的动画设计应尽量在这个持续时间内完成,以避免动画被截断或过早结束。建议值为 200ms 到 1000ms 之间,保持快速且流畅。
5. 品牌 Logo:windowSplashScreenBrandDrawable
(可选)
- 类型: Drawable 引用
- 作用: 在启动画面底部显示一个可选的品牌 Logo。
- 位置: 这个 Logo 会固定显示在启动画面的底部,不会随图标一起动画。
- 用处: 适合展示公司或产品的额外品牌标识。
6. 核心属性:postSplashScreenTheme
- 类型: Style 引用(
@style/
) - 作用: 这是最重要的属性!它指定了启动画面结束后,Activity 应该切换到哪个主题来渲染你的应用界面。
- 重要性: 如果没有正确设置这个属性,你的 Activity 在启动画面消失后,可能会显示错误的样式,甚至出现界面空白或闪烁。务必将其指向你应用正常运行时所使用的主要主题。
二、应用开发实践:从零开始配置
让我们通过一个完整的示例,一步步将 Android 12 的启动画面集成到你的应用中。
1: 确保你的项目兼容 Android 12 (SDK 31+)
首先,在你的 build.gradle (Module: app)
文件中,确保 compileSdk
和 targetSdk
至少是 31:
android {
compileSdk 31 // 或更高版本
defaultConfig {
targetSdk 31 // 或更高版本
// ...
}
// ...
}
2. 添加 Splash Screen 库依赖
dependencies {
// ... 其他依赖
implementation 'androidx.core:core-splashscreen:1.0.1'
}
3. 定义你的应用主题
在 res/values/themes.xml
(和 res/values-night/themes.xml
,用于深色模式) 中定义应用主主题。这将是 postSplashScreenTheme
指向的主题。
<resources>
<style name="Theme.MyAwesomeApp" parent="Theme.MaterialComponents.DayNight.NoActionBar">
<item name="colorPrimary">#6200EE</item>
<item name="colorPrimaryVariant">#3700B3</item>
<item name="colorOnPrimary">#FFFFFF</item>
<item name="colorSecondary">#03DAC6</item>
<item name="colorSecondaryVariant">#018786</item>
<item name="colorOnSecondary">#000000</item>
<item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
<item name="android:navigationBarColor">@color/black</item>
<item name="android:windowBackground">@color/white</item>
</style>
</resources>
<resources>
<style name="Theme.MyAwesomeApp" parent="Theme.MaterialComponents.DayNight.NoActionBar">
<item name="colorPrimary">#BB86FC</item>
<item name="colorPrimaryVariant">#3700B3</item>
<item name="colorOnPrimary">#000000</item>
<item name="colorSecondary">#03DAC6</item>
<item name="colorSecondaryVariant">#03DAC6</item>
<item name="colorOnSecondary">#000000</item>
<item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
<item name="android:navigationBarColor">@color/black</item>
<item name="android:windowBackground">@color/dark_gray</item>
</style>
</resources>
4. 准备启动画面背景(渐变色和Logo)
我们创建一个 LayerList
来实现一个包含渐变背景和底部品牌Logo的启动画面。(实际上不推荐 用渐变色,我更推荐telegram或者X的方案,纯色背景+AVD/静态LOGO)
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="[http://schemas.android.com/apk/res/android](http://schemas.android.com/apk/res/android)">
<item>
<shape android:shape="rectangle">
<gradient
android:angle="270"
android:startColor="#6200EE"
android:endColor="#03DAC6"
android:type="linear" />
</shape>
</item>
<item android:bottom="32dp"> <bitmap
android:src="@drawable/ic_my_company_logo"
android:gravity="bottom|center_horizontal" />
</item>
</layer-list>
注意:
@drawable/ic_my_company_logo
应该是你的 Logo 图片(Vector Drawable 或 Bitmap)。android:bottom
可以调整 Logo 的位置。android:gravity="bottom|center_horizontal"
将 Logo 放置在底部中央。
5. 准备启动画面动画图标(AVD 示例)
假设你已经有一个名为 ic_animated_logo.xml
的 Animated Vector Drawable。
<?xml version="1.0" encoding="utf-8"?>
<animated-vector xmlns:android="[http://schemas.android.com/apk/res/android](http://schemas.android.com/apk/res/android)"
android:drawable="@drawable/ic_static_logo"> <target android:name="group_name_in_static_logo"> <propertyValuesHolder
android:propertyName="rotation"
android:valueFrom="0"
android:valueTo="360"
android:valueType="floatType"
android:duration="1000"
android:interpolator="@android:interpolator/fast_out_slow_in" />
</target>
</animated-vector>
如果不想使用自定义动画,直接使用自适应图标前景部分:@mipmap/ic_launcher_foreground
。
6. 定义启动画面主题
现在,在 res/values/themes.xml
(和 res/values-night/themes.xml
) 中定义你的启动主题,并引用我们准备好的 Drawable。
<resources>
<style name="Theme.MyAwesomeApp.SplashScreen" parent="Theme.SplashScreen">
<item name="windowSplashScreenBackground">@drawable/splash_layer_bg</item>
<item name="windowSplashScreenAnimatedIcon">@drawable/ic_animated_logo</item>
<item name="windowSplashScreenAnimationDuration">1000</item> <item name="postSplashScreenTheme">@style/Theme.MyAwesomeApp</item>
</style>
</resources>
<resources>
<style name="Theme.MyAwesomeApp.SplashScreen" parent="Theme.SplashScreen">
<item name="windowSplashScreenBackground">@color/dark_splash_bg_color</item>
<item name="windowSplashScreenAnimatedIcon">@drawable/ic_animated_logo_dark</item>
<item name="windowSplashScreenAnimationDuration">1000</item>
<item name="postSplashScreenTheme">@style/Theme.MyAwesomeApp</item>
</style>
</resources>
7. 在 AndroidManifest.xml
中应用主题
在 AndroidManifest.xml
中,将 Theme.MyAwesomeApp.SplashScreen
主题应用到启动 Activity(通常是 MainActivity
,也有可能是SplashActivity
之类的)。
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="[http://schemas.android.com/apk/res/android](http://schemas.android.com/apk/res/android)"
xmlns:tools="[http://schemas.android.com/tools](http://schemas.android.com/tools)">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.MyAwesomeApp"> <activity
android:name=".MainActivity"
android:exported="true"
android:theme="@style/Theme.MyAwesomeApp.SplashScreen"> <intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".OtherActivity"
android:theme="@style/Theme.MyAwesomeApp"/>
</application>
</manifest>
8. 在 MainActivity
中安装启动画面
最后,在启动 Activity 的 onCreate()
方法中调用 installSplashScreen()
。这是启用系统启动画面 API 的核心步骤。
// MainActivity.kt
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.withContext
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.launch
class MainActivity : AppCompatActivity() {
private var isContentReady = false // 用于控制启动画面何时消失
override fun onCreate(savedInstanceState: Bundle?) {
// 1. 调用 installSplashScreen() 必须在 super.onCreate() 之前
val splashScreen = installSplashScreen()
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// 2. 延迟启动画面消失,直到内容准备就绪
splashScreen.setKeepOnScreenCondition {
!isContentReady // 当 isContentReady 为 false 时,启动画面会一直显示
}
// 3. 模拟数据加载或应用初始化
loadAppContent()
}
private fun loadAppContent() {
lifecycleScope.launch(Dispatchers.IO) {
// 模拟耗时的初始化操作,例如网络请求、数据库加载等
delay(3000) // 模拟 3 秒的加载时间
// 数据加载完成
isContentReady = true
withContext(Dispatchers.Main) {
// 在这里可以执行数据加载完成后的 UI 更新或跳转操作
// 例如:navigateToHome()
}
}
}
}
Java 示例(AI转换的代码,应该咩问题):
// MainActivity.java
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.splashscreen.SplashScreen;
import android.os.Handler;
import android.os.Looper;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class MainActivity extends AppCompatActivity {
private boolean isContentReady = false; // 用于控制启动画面何时消失
@Override
protected void onCreate(Bundle savedInstanceState) {
// 1. 调用 installSplashScreen() 必须在 super.onCreate() 之前
SplashScreen splashScreen = SplashScreen.Companion.installSplashScreen(this);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 2. 延迟启动画面消失,直到内容准备就绪
splashScreen.setKeepOnScreenCondition(() -> !isContentReady);
// 3. 模拟数据加载或应用初始化
loadAppContent();
}
private void loadAppContent() {
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
executor.schedule(() -> {
// 模拟耗时的初始化操作
isContentReady = true; // 数据加载完成
new Handler(Looper.getMainLooper()).post(() -> {
// 在主线程执行数据加载完成后的 UI 更新或跳转操作
});
}, 3, TimeUnit.SECONDS); // 模拟 3 秒的加载时间
}
}