从0到1打造一款安卓app之5-启动页
1.启动页黑/白屏问题处理
假如应用启动很慢(虽然在开发过程中要尽量避免,并且要优化),应用未启动时,从点击桌面图标打开应用,会有一瞬间的黑/白屏出现
我们可以手动模拟这一情况
class MainApplication : BaseApplication() {
override fun onCreate() {
super.onCreate()
//模拟启动慢
Thread.sleep(4500)
}
}
处理方式
设置<item name="android:background">@drawable/splash_background_layer_list</item>
<style name="fullscreenNoTitleTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar">
<item name="android:windowFullscreen">true</item>
<item name="android:windowNoTitle">true</item>
<item name="android:background">@drawable/splash_background_layer_list</item>
</style>
<activity
android:name=".ui.SplashActivity"
android:exported="true"
android:theme="@style/fullscreenNoTitleTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
2.启动页背景图片拉伸变形问题处理
设置<item name="android:background">@drawable/splash_background_layer_list</item>这种处理方式虽然可以避免黑/白屏问题出现,但是一个不太好处理的是,background;默认是拉伸的,如果图片宽高比例和屏幕宽高比例差太多,背景会明显变形。
手机屏幕尺寸多种多样,但常见屏幕尺寸只有比例两种,可以做两种比例的背景图,拉伸起来就不会那么明显了。
长宽比为1.6~1.8之间的 ,800x1280px ,768x1280px,1080x1920px
全面屏流行之后,屏幕长宽比约等于2.0~2.2之间,2400x1080px
虽然比例只在这几个范围内,但是屏幕尺寸实在太多,各种各样,还是会出现拉伸的情况,可以使用layer-list处理,一张图片作为背景图填充拉伸(比例差不太多情况下,拉伸并不会太明显),一张图片作为logo前景不拉伸,layer-list里的bitmap不支持使用drawable里的xml作为资源,否则会报资源找不到。
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<bitmap
android:src="@mipmap/splash_background"
android:antialias="true"
android:gravity="fill"/>
</item>
<item>
<bitmap
android:src="@mipmap/ic_logo"
android:gravity="center"
android:antialias="true"/>
</item>
</layer-list>
3.安卓12新增的 SplashScreen API,
在res文件夹下,新建 values-v31 并且新建themes.xml文件,v31即安卓12
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="fullscreenNoTitleTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar">
<item name="android:windowFullscreen">true</item>
<item name="android:windowNoTitle">true</item>
<!-- <item name="android:background">@drawable/splash_background_layer_list</item>-->
<item name="android:windowSplashScreenBackground">@color/white</item>
<item name="android:windowSplashScreenAnimatedIcon">@drawable/ic_help_other</item>
<item name="android:windowSplashScreenAnimationDuration">1000</item>
<item name="android:windowSplashScreenIconBackgroundColor">@color/white</item>
<item name="android:windowSplashScreenBrandingImage">@mipmap/splash_background</item>
</style>
</resources>
让启动画面在屏幕上显示更长时间
当应用绘制第一帧后,启动画面会立即关闭。如果您需要从本地磁盘异步加载少量数据(如应用内主题设置),您可以使用 ViewTreeObserver.OnPreDrawListener 让应用暂停绘制第一帧。
// 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 {
//如果不removeOnPreDrawListener,这里会一直回调
// Check if the initial data is ready.
return if (viewModel.isReady) {
// The content is ready; start drawing.
content.viewTreeObserver.removeOnPreDrawListener(this)
true
} else {
// The content is not ready; suspend.
false
}
}
}
)
}
自定义用于关闭启动画面的动画
您可以通过 Activity.getSplashScreen 进一步自定义启动画面的动画。
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()
}
}
在此回调开始时,启动画面上动画形式的矢量可绘制对象已经开始。根据应用启动的时长,可绘制对象可能在其动画的中间。使用 SplashScreenView.getIconAnimationStartMillis 可了解动画何时开始。您可以按如下方式计算图标动画的剩余时长:
// Get the duration of the animated vector drawable.
val animationDuration = splashScreenView.iconAnimationDurationMillis
// Get the start time of the animation.
val animationStart = splashScreenView.iconAnimationDurationMillis
// Calculate the remaining duration of the animation.
val remainingDuration = (
animationDuration - (SystemClock.uptimeMillis() - animationStart)
).coerceAtLeast(0L)
4.使状态栏透明并隐藏状态栏文字
BarUtils.transparentStatusBar(this)
ViewCompat.getWindowInsetsController(activitySplashBinding.root)?.hide(WindowInsetsCompat.Type.systemBars())