UItempAndroid

AndroidX SplashScreen:全新App启动页面

2021-11-07  本文已影响0人  goodl

Android 12 添加了 SplashScreen API,它可为所有应用启用新的应用启动动画。这包括启动时的进入应用运动、显示应用图标的启动画面,以及向应用本身的过渡。

Android 12 上效果固然不错,可如果不兼容低版本系统的话,实属鸡肋。
AndroidX 推出了一个叫 SplashScreen 的同名 API,很显然它就是用来兼容低版本的 SplashScreen 功能库。

现在 App 大多点击图标启动后,一般都会有几个固定的界面:

abc.png

如果不适配 SplashScreen,在 Android 12 上,系统默认为 App 生成的启动页,加上 App 自身的启动页,就会有两个启动页,显然不是我们期望的效果。
同时为了兼容低版本,这时候就需要引入 SplashScreen 库:

1.0 引入 SplashScreen 库

目前最新版本为 1.0.0-alpha02,可在 官网 查询最新版本

implementation "androidx.core:core-splashscreen:1.0.0-beta01"

1.1 添加样式

themes.xml:

<style name="Theme.TestSplashScreen.Starting" parent="Theme.SplashScreen">
    # 启动画面的背景,默认使用 windowBackground
    <item name="windowSplashScreenBackground">@color/...</item>
    # 指定 icon,支持静态 drawable 或动画 vector drawable
    <item name="windowSplashScreenAnimatedIcon">@drawable/...</item>
    # 动画 icon 时长,上限 1000 ms
    <item name="windowSplashScreenAnimationDuration">1000</item>
    # 启动画面退出后 Activity 的主题
    <item name="postSplashScreenTheme">@style/Theme.TestSplashScreen.Launcher</item>
</style>

<style name="Theme.TestSplashScreen.Launcher">
    <item name="windowActionBar">false</item>
    <item name="windowNoTitle">true</item>
    <item name="android:windowTranslucentStatus">true</item>
    <item name="android:windowTranslucentNavigation">true</item>
</style>

AndroidManifest.xml:

<activity
    android:name=".LauncherActivity"
    android:exported="true"
    android:screenOrientation="portrait"
    android:theme="@style/Theme.TestSplashScreen.Starting">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

1.2 修改现有的启动页 LauncherActivity

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    val splashScreen = installSplashScreen() // 在 setContentView 之前调用
    setContentView(R.layout.activity_launcher) // 可选,可删除该行
    ...
}

这样最基本的适配就结束了。

2.2 延长启动页面

通过 SplashScreen#setKeepVisibleCondition 延长启动页

private var keepOnScreen = AtomicBoolean(true)

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    val splashScreen = installSplashScreen()
    setContentView(R.layout.activity_launcher)

    lifecycleScope.launch {
        delay(2000)
        keepOnScreen.compareAndSet(true, false)
    }
    splashScreen.setKeepOnScreenCondition { keepOnScreen.get() }
}

这样,启动页延长至 2 秒

2.2 定制启动页退场动画

通过 SplashScreen#setOnExitAnimationListener 设置动画效果
这里分别设置了,SplashScreen 页面和中间 icon 的退场动画

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    val splashScreen = installSplashScreen()
    setContentView(R.layout.activity_launcher)

    splashScreen.setOnExitAnimationListener { provider ->
        showSplashIconExitAnimator(provider.iconView)
        // 两个动画的时长可以不一样,这里监听 splashScreen 动画结束
        showSplashExitAnimator(provider.view) {
            provider.remove()
            // 进入主界面,顺便给个 FadeOut 退场动画
            startActivity(Intent(this, MainActivity::class.java))
            finish()
            overridePendingTransition(0, R.anim.fade_out)
        }
    }
}

// splash screen view 退场动画:透明度 + 揭露
private fun showSplashExitAnimator(view: View, onExit: () -> Unit) {
    val alphaOut = ObjectAnimator.ofFloat(view, View.ALPHA, 1f, 0.2f)

    val cx = view.width / 2
    val cy = view.height / 2
    // get the start radius for the clipping circle
    val startRadius = hypot(cx.toDouble(), cy.toDouble()).toFloat()
    val revealOut = ViewAnimationUtils.createCircularReveal(
        view, cx, cy, startRadius, 0f
    )

    AnimatorSet().apply {
        duration = 300
        interpolator = DecelerateInterpolator()
        playTogether(alphaOut, revealOut)
        doOnEnd { onExit() }
    }.also { it.start() }
}

// splash icon 退场动画:透明度 + 缩放
private fun showSplashIconExitAnimator(view: View) {
    val alphaOut = ObjectAnimator.ofFloat(view, View.ALPHA, 1f, 0.2f)
    val scaleOut = ObjectAnimator.ofFloat(
        view,
        View.SCALE_X,
        View.SCALE_Y,
        Path().apply {
            moveTo(1f, 1f)
            lineTo(0.2f, 0.2f)
        }
    )

    AnimatorSet().apply {
        duration = 300
        interpolator = DecelerateInterpolator()
        playTogether(alphaOut, scaleOut)
    }.also { it.start() }
}

参考:
https://developer.android.com/guide/topics/ui/splash-screen/migrate
https://developer.android.com/about/versions/12/features/splash-screen

上一篇下一篇

猜你喜欢

热点阅读