嘿嘿,你好啊
-
- 1.为啥会出现这个页面
- 2.效果图
- 3.为啥标题这么长
- [4.最佳解决方案:无缝过渡(Themed Launch Screen)](#4.最佳解决方案:无缝过渡(Themed Launch Screen))
说起来,这是一个咱们Android开发中,非常经典的一个问题,通常就是叫"冷启动白屏/黑屏问题"(Cold Start White/Black Screen)。然后看到的第一个"新加的页面",其实并不是咱们开发者主动增加的activity,而是Android系统给自动生成的"预览窗口"(Starting Window)。
1.为啥会出现这个页面
当用户点击app图片来启动App时,我们都知道Android系统需要做很多准备工作,如加载app进程、加载DEX文件、初始化application等等,这个过程是需要一定的加载时间的,通常就是几十毫秒到几秒。
然后呢,Android系统为了不让用户觉得点击图标后手机"死机"了或者没反应,系统就会立即弹出一个预览窗口,用来先及时响应一下用户的指令
2.效果图
原始效果

方案2效果:

方案3效果:

3.为啥标题这么长
哈哈哈哈,搞这么长个题目,实在也是属于无奈之举。因为国内厂商系统碎片化严重,各种厂商的各种定制系统,例如:小米的MIUI、HyperOS,oppo的ColorOS,华为的HarmonyOS等等。导致对Android系统来说是同一个问题的东西,在不同的厂商手机上,可能会有不一样的表现。
如果不做任何适配,比方说(目前发现问题的),
- OPPO:可能是他们为了提升用户体验,然后系统自动检测咱们项目中的APP图标,然后给放到预览窗口的中间,模仿一个启动页,所以就有了最后一个"or"
- 其他:其他的手机就是根据默认的主题背景色,然后会有一个白屏或者黑屏的显示
4.最佳解决方案:无缝过渡(Themed Launch Screen)
首先哈,建议不要试图去"消除"这个窗口(就比如说,你如果把这个预览窗口设为透明,那样确实不会有白屏黑屏啥的了,但是用户点击icon后,会感觉手机卡顿了一下才出现了你的SplashActivity,对于体验来说,甚至不如有个白屏了)。
经多对市场上的一些热门app的体验调研,我发现现在市面上大概有三种情况,
- 第一种就是先不管,点一下有个白屏,全部交给系统
- 第二种是设计一个背景色,然后加一个自己的logo,相当于简单自定义一下这个页面,更价贴合app主题
- 第三种则是将startingwindow直接替换成一整张图片
第一种肯定不用管,首先我们先说一下第二种,实现完毕之后就是:
点击icon ->瞬间展示贴合主题的页面->然后代码逻辑开始运行了,体验很丝滑美妙
ffs
- 第一步:添加依赖(build.gradle)
在 app/build.gradle 文件中添加库的依赖:
xml
dependencies {
implementation "androidx.core:core-splashscreen:1.0.1"
}
- 第二步:配置主题 (themes.xml)
咱们需要自定义一个专门的启动主题。这个主题用来自定义启动页长什么样
打开 res/values/themes.xml (或 styles.xml):
xml
<style name="Theme.App.Starting" parent="Theme.SplashScreen">
<!-- 背景色-->
<item name="windowSplashScreenBackground">@color/white</item>
<!-- 背景中间的的图片-->
<item name="windowSplashScreenAnimatedIcon">@drawable/startcenter</item>
<!--启动页结束后」,App 主界面要切换到的目标主题-->
<item name="postSplashScreenTheme">@style/Theme.YourApp.Normal</item>
</style>
<style name="Theme.YourApp.Normal" parent="Theme.MaterialComponents.DayNight.NoActionBar">
<item name="colorPrimary">@color/purple_500</item>
</style>
- 第三步:修改 AndroidManifest.xml
将项目中的入口activity,我的demo中是SplashActivity的主题,替换成咱们上面上自定义的主题
xml
<activity
android:name=".ui.startingwindow.SplashActivity"
android:exported="true"
android:theme="@style/Theme.App.Starting">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
- 第四步:运行
嘿嘿嘿,逗你玩儿,这个时候你会惊喜的发现,诶?startwindow设置明白了,怎么报错呢?欲知为何报错,请看下章第五步
xml
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.blogdemoapplication/com.example.blogdemoapplication.ui.startingwindow.SplashActivity}: java.lang.IllegalStateException: You need to use a Theme.AppCompat theme (or descendant) with this activity.
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:4410)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:4631)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:112)
at android.app.servertransaction.TransactionExecutor.executeNonLifecycleItem(TransactionExecutor.java:186)
at android.app.servertransaction.TransactionExecutor.executeTransactionItems(TransactionExecutor.java:112)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:84)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2873)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loopOnce(Looper.java:249)
at android.os.Looper.loop(Looper.java:337)
at android.app.ActivityThread.main(ActivityThread.java:9580)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:593)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)
Caused by: java.lang.IllegalStateException: You need to use a Theme.AppCompat theme (or descendant) with this activity.
at androidx.appcompat.app.AppCompatDelegateImpl.createSubDecor(AppCompatDelegateImpl.java:902)
at androidx.appcompat.app.AppCompatDelegateImpl.ensureSubDecor(AppCompatDelegateImpl.java:865)
at androidx.appcompat.app.AppCompatDelegateImpl.setContentView(AppCompatDelegateImpl.java:748)
at androidx.appcompat.app.AppCompatActivity.setContentView(AppCompatActivity.java:193)
at com.example.blogdemoapplication.ui.startingwindow.SplashActivity.onCreate(SplashActivity.kt:21)
at android.app.Activity.performCreate(Activity.java:9221)
at android.app.Activity.performCreate(Activity.java:9177)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1538)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:4392)
... 13 more
- 在代码中初始化
这是最重要的一步。你必须在 super.onCreate() 之前调用 installSplashScreen()。
kotlin:
xml
override fun onCreate(savedInstanceState: Bundle?) {
val splashScreen = installSplashScreen()
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// ... 你的初始化代码
}
下面是咱们用java的同学看的:
xml
protected void onCreate(Bundle savedInstanceState) {
SplashScreen splashScreen = SplashScreen.installSplashScreen(this);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// ...你的初始化代码
}
问题是解决了,那么有些喜欢观察的兄弟们说了, 我咋看有的app直接就是一个中间图片,然后底部还有个他们的Slogan啊,这博主藏着掖着的,不好好写是吧。别着急,兄弟们,没上来就说,其实是因为,底部添加图片的话,会在Android12上下有一个兼容性限制,比方说:
- 新手机(Android 12+):显示中间Logo+底部图片
- 旧手机(Android 11-):只显示中间Logo,底部图片会被自动忽略
如果能接受这种差异的话(当然凡是底部有图片的,也都是这么做的),请看下面详情解析:
- 首先你需要准备一张图片(建议是透明背景的PNG或SVG),我是demo只是为了展示功能。因为这个新的配置是Android12+的,所以你需要在values的同级目录新建一个values-v31,然后再创建一个themes.xml(styles.xml),原来themes.xml中的不变:
xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Theme.App.Starting" parent="Theme.SplashScreen">
<!-- 背景色-->
<item name="windowSplashScreenBackground">@color/white</item>
<!-- 背景中间的的图片-->
<item name="windowSplashScreenAnimatedIcon">@drawable/startcenter</item>
<!-- 背景底部的的图片-->
<item name="android:windowSplashScreenBrandingImage">@drawable/startingbom</item>
<!--启动页结束后」,App 主界面要切换到的目标主题-->
<item name="postSplashScreenTheme">@style/Theme.YourApp.Normal</item>
</style>
</resources>
注意:
对图片的一些要求:如果底部这张图太大,系统就可能不显示或者裁剪的及其难看,查了一些资料,看到推荐尺寸是:高度不要超过80dp,宽度不超过200dp,长宽比建议是2.5:1,内功的话,不要有太多透明边距
方案2终于是告一断落,接下来我们说一下方案3,看过官方文档并且细心的小伙伴应该能发现,理论上来说,绝对的替换成一张图片,Google是不支持的,因为官方最新标准,新 Splash API (core-splashscreen) 强制规定背景只能是颜色,不能是图片。并且中间必须是 Icon。所以理论上来说,方案3是不可行的。
但是虽然Google强推新标准,但是国内厂商(小米,OPPO,华为等)的ROM对"传统方式"的兼容性很好,为了视觉效果,国内很多app就依旧使用的传统方案。即:android:windowBackground 来设置背景图片,接下来说说完整步骤:
- 搞一张背景图
起个名字,比如说splashbg.png,放到drawable目录下面 - 定义传统 Splash 主题
在 themes.xml 中定义一个主题,然后将上面提到的 windowBackground 设为图片,并将状态栏设为透明以实现沉浸式效果
xml
<style name="Theme.App.FullSplash" parent="Theme.MaterialComponents.Light.NoActionBar">
<!-- 背景图-->
<item name="android:windowBackground">@drawable/splashbg</item>
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:windowTranslucentStatus">true</item> </style>
- 应用到 Activity
xml
<activity
android:name=".ui.startingwindow.SplashActivity"
android:exported="true"
android:theme="@style/Theme.App.FullSplash">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
这就是背景是一整张图片的实现方案了,上面也说了,国内厂商兼容的挺好,但是就意味着,在原生 Android 12+如Pixel 手机上就会失效,然后变成纯色+logo的效果,看能不能接受了。
我是入梦,谢谢你的观看我的博客,觉着好用的话,麻烦帮忙点个赞呗,谢谢啦~ 如果有什么错误,请随时联系我噢~QQ:897589417