Android 12以上加入了SplashScreen,并且支持开屏动画了!因此我在【小鹅事务所】项目中加入了一个开屏动画,如下(为方便动图展示,我故意延长了几秒钟):
SplashScreen
简单介绍一下SplashScreen,仅在冷启动或者温启动的时候会展示SplashScreen,支持AVD动画、帧动画。我就先使用帧动画实现这个开屏动画,后面会考虑换成AVD动画。关于SplashScreen具体就不细讲啦,我讲这些讲不明白,没有官方文档讲得好,直接进入实战!!
注意裁切
ICON在设计的时候只能够占用三分之二大小的圆,超出这部分的会被裁切掉,所以这点需要注意!
设计
首先打开UI设计软件,我此处用Figma,新建一个方形的框框,方形的框框里面整一个三分二大小的圆圈,像这样。
然后呢,就把设计好的Icon放进去
这个时候一张静态图就做好啦,但是帧动画需要让图片动起来的话,就需要多张静态图。怎么设计它动起来呢?我的思路是让它扭头!像这样。
然后再把框框的颜色隐藏掉,我们只需要透明背景的Icon
注意,为了展示外边需要留空间,我给它们的框框加上描边,实际不需要!这个时候就可以导出图片啦,我这边选择导出矢量图,也就是SVG格式。
导入动画
打开Android Studio,右键点击res → new → Vector Asset,再导入图片,将静态图都导进去就可以做动画啦。
新建anim_little_goose.xml
,根标签是animation-list
,并在里面放4个item。
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false">
<item
android:drawable="@drawable/ic_little_goose"
android:duration="50" />
<item
android:drawable="@drawable/ic_little_goose_back"
android:duration="150" />
<item
android:drawable="@drawable/ic_little_goose"
android:duration="50" />
<item
android:drawable="@drawable/ic_little_goose_fore"
android:duration="150" />
</animation-list>
根据命名可以看出
-
第一帧为正常的小鹅,展示50毫秒
-
第二帧为向后扭头的小鹅,展示150毫秒
-
第三帧为正常的小鹅,展示50毫秒
-
第四帧为向前扭头的小鹅,展示150毫秒
一次循环就是400毫秒,点开Split界面,就能在右边预览动画了,这个时候,动画就简简单单做好了。
SplashScreen
引入依赖
由于SplashScreen是Android12以上才有的,而Android12以下需要适配,但是!Jetpack提供了同名适配库,去gradle引用就好了。
//SplashScreen
implementation 'androidx.core:core-splashscreen:1.0.0'
设置开屏主题
然后在res/values/themes
中新建一个style标签,并将其父标签设为Theme.SplashScreen
,需要注意的是,如果适配了黑夜模式的话,也可以在values-night/themes
文件下单独配置。
<style name="Theme.AppSplashScreen" parent="Theme.SplashScreen">
<item name="windowSplashScreenBackground">@color/primary_color</item>
<item name="windowSplashScreenAnimatedIcon">@drawable/anim_little_goose</item>
<item name="windowSplashScreenAnimationDuration">3000</item>
<item name="postSplashScreenTheme">@style/Theme.Account</item>
</style>
我这边配置一个无ICON背景的动画,因此不用windowSplashScreenIconBackgroundColor
标签设置ICON背景。
简单介绍一下我设置的4个标签
-
windowSplashScreenBackground
设置整个开屏动画的背景颜色。 -
windowSplashScreenAnimatedIcon
设置的是开屏动画播放的动画文件,也就是上面写的动画文件。 -
windowSplashScreenAnimationDuration
设置的是动画的播放时长,也就是说小鹅抖三秒钟头就会停止播放。 -
postSplashScreenTheme
这个设置的是开屏动画播放完需要回到的主题,此处设置了我的主题。<style name="Theme.Account" parent="Theme.MaterialComponents.DayNight.NoActionBar"> ... </style>
在Manifest注册
<application
android:label="@string/app_name"
...
android:theme="@style/Theme.Account">
...
<activity
android:name=".ui.MainActivity"
android:theme="@style/Theme.AppSplashScreen"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
可以看到在打开应用打开的第一个Activity,即MainActivity中设置了开屏主题,而在Application中设置了自己的主题。在Application设置主题的话,这个Application中的除了特殊设置Theme的Activity,其它都默认使用Application主题。
去MainActivity吧!
class MainActivity : BaseActivity() {
private val binding by viewBinding(ActivityMainBinding::inflate)
override fun onCreate(savedInstanceState: Bundle?) {
val splashScreen = installSplashScreen()
splashScreen.setKeepOnScreenCondition { !isAppInit }
super.onCreate(savedInstanceState)
initView()
}
...
}
重写onCreate
函数,并在调用super.onCreate
之前加载SplashScreen,即调用installSplashScreen
,获得一个splashScreen实例,理论上来说调用installSplashScreen
函数已经可以实现开屏动画了,可是我想等到一部分数据加载完再进入APP怎么办?
可以看到我调用了setKeepOnScreenCondition
函数,传入一个接口,这个接口返回一个Boolean值,如果返回true则继续展示开屏,如果返回false则进入APP。而此函数在每次绘制之前都会调用,是主线程调用的,因此不能在这里处理太多东西阻塞主线程!
我这边就设置了一个顶层变量,每次都去看看这个顶层变量的值,不会阻塞主线程。
class AccountApplication : Application() {
val supervisorScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
//初始化数据 防止第一次打开还要加载
private fun initData() {
supervisorScope.launch {
val initIconDataDeferred = async { TransactionIconHelper.initIconData() }
val initTransactionDeferred = async { TransactionHelper.initTransaction() }
val initScheduleDeferred = async { ScheduleHelper.initSchedule() }
val initNoteDeferred = async { NoteHelper.initNote() }
val initMemorialsDeferred = async { MemorialHelper.initMemorials() }
val initTopMemorialDeferred = async { MemorialHelper.initTopMemorial() }
val initDataStoreDeferred = async { DataStoreHelper.INSTANCE.initDataStore() }
initIconDataDeferred.await()
initTransactionDeferred.await()
initScheduleDeferred.await()
initNoteDeferred.await()
initMemorialsDeferred.await()
initTopMemorialDeferred.await()
initDataStoreDeferred.await()
isAppInit = true
}
}
}
var isAppInit = false
我在Application中对所有需要初始化的东西先初始化一遍,初始化完之后再将isAppInit
设置为true,此时在闪屏那边获取的为false,也就是说就会进入APP了。
到这里就结束了,去运行一下吧!
总结
说实话,在我看来,SplashScreen其实用处不大,因为我们的闪屏一般是用来放advertisement的,而不是放有趣的动画的!
参考
SplashScreen: developer.android.google.cn/develop/ui/…