Jetpack新成员SplashScreen:为全新的应用启动效果赋能!(1)

简介: Jetpack新成员SplashScreen:为全新的应用启动效果赋能!(1)

Android 12上新引入的Splash Screen功能,可以高效打造自由、丰富的应用启动效果。但仍占据市场主流的低版本设备,如何才能尝上鲜呢?答案就是Jetpack的新成员SplashScreen库,让我们一探其用法以及背后的原理!

前言

早在Android 12 Preview版公开的时候,我注意到了酷炫的Splash Screen功能,便快速定制和分享了用它打造的各式启动效果,收到了很多积极的反馈。万分荣幸的是:负责Splash Screen功能的Google工程师也给我的Demo点了赞,还进行了转发!

1672153281712.png

但不少开发者表示Android 12上的效果固然不错,可12之前的版本才是主流,如果不兼容的话,实属有些鸡肋。包括我在内,都很关心低版本如何才能应用上这个新功能。


翻阅这位Google工程师的历史推文的时候,意外发现不久前AndroidX包也刚推出了一个叫SplashScreen的同名API。我们都知道AndroidX归属Jetpack,是独立于SDK版本以外的开发框架集合,很显然它就是用来兼容低版本的Splash Screen功能库。

1832b220aa754cd18c504acc7686a560.png

这可谓是及时雨啊,必须研究一下,让Splash Screen功能充分发挥它的作用!加上之前分享的文章没有提及实现原理,本文一并探讨一下。

1. 新成员SplashScreen

Jetpack SplashScreen是向后兼容Android 12 Splash Screen功能的开发库。 其最早支持到Android 6(API 23),全球的Android设备中6及以上的版本占用率达到了9成以上,可以说完全够用了。

1.1 作用以及局限

Splash Screen功能打造的启动画面分为进场退场两部分:前者负责展示Icon、Icon动画以及品牌Logo等基本信息,后者则用于展示整体或Icon视图过渡到目标画面的动画效果。

1832b220aa754cd18c504acc7686a560.png

对于退场部分而言,无论是否运行在12上,Jetpack SplashScreen库都能达到Android 12同等效果;但进场部分如果是运行在低版本上,暂时存在些局限。


暂不支持展示Icon动画:AnimatedVectorDrawable

暂不支持配置Icon背景:IconBackgroundColor

暂不支持设置品牌Logo:BrandingImage

1672153369902.png

备注:后面会讲到SplashScreen库的实现原理,面向低版本的进场效果本质上是一个LayerDrawable。说实话,对于支持Vector Drawable动画、Adaptive Icon背景是无能为力的。但笔者认为在代码层面加入些额外处理,是可以做到完美支持的,期待后期升级能完善一下!

2.2 导入依赖

SplashScreen库的最新版本为1.0.0-alpha01,Gradle里简单依赖即可。

dependencies {
    def core_version = "1.6.0"
    ...
    // Optional - APIs for SplashScreen, including compatiblity helpers on devices prior Android 12
    implementation "androidx.core:core-splashscreen:1.0.0-alpha01"
}

2.3 SplashScreen库预设主题

SplashScreen库针对启动画面的打造定义了专用的Attr,比如设置Icon和画面背景的windowSplashScreenAnimatedIcon和windowSplashScreenBackground,以及设置启动画面退出后Activity主题的postSplashScreenTheme等。


低版本并不支持Icon动画,也就谈不上配置时长,但库还是提供了相关的属性windowSplashScreenAnimationDuration,原因不太清楚。

<attr format="reference" name="postSplashScreenTheme"/>
<attr format="reference" name="windowSplashScreenAnimatedIcon"/>
<attr format="integer" name="windowSplashScreenAnimationDuration"/>
<attr format="color" name="windowSplashScreenBackground"/>

此外为了简化App端的配置,还预设了主题,同时并针对设备版本进行了区分。

如下是面向低版本的主题:

<style name="Theme.SplashScreen" parent="Theme.SplashScreenBase">
    <item name="postSplashScreenTheme">?android:attr/theme</item>
    <item name="windowSplashScreenAnimationDuration">@integer/default_icon_animation_duration</item>
    <item name="windowSplashScreenBackground">@android:color/background_light</item>
    <item name="windowSplashScreenAnimatedIcon">@android:drawable/sym_def_app_icon</item>
</style>
<style name="Theme.SplashScreenBase" parent="android:Theme.NoTitleBar">
    <item name="android:windowBackground">@drawable/compat_splash_screen</item>
    <item name="android:opacity">opaque</item>
    <item name="android:windowDrawsSystemBarBackgrounds">true</item>
    <item name="android:fitsSystemWindows">false</item>
    <item name="android:statusBarColor">@android:color/transparent</item>
    <item name="android:navigationBarColor">@android:color/transparent</item>
</style>

比较关键的是父主题SplashScreenBase设置了windowBackground属性,其指向的Drawable负责展示低版本的启动画面。


原理很简单:读取windowSplashScreenBackground设置的背景ColorDrawable和windowSplashScreenAnimatedIcon设置的图标Drawable,图标 Drawable放置到背景Drawable的中央,然后组合成Layer Drawable。老实说,跟我们以前自定义启动画面的思路是类似的。

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:gravity="fill">
        <color android:color="?attr/windowSplashScreenBackground" />
    </item>
    <item
        android:drawable="?attr/windowSplashScreenAnimatedIcon"
        android:gravity="center"
        android:width="@dimen/splashscreen_icon_size"
        android:height="@dimen/splashscreen_icon_size" />
</layer-list>

因12版本提供了Splash Screen功能的系统属性,所以针对12及以上的主题,只需要将库定义的属性转化为系统属性。

<style name="Theme.SplashScreen" parent="android:Theme.DeviceDefault.NoActionBar">
    <item name="android:windowSplashScreenAnimatedIcon">?windowSplashScreenAnimatedIcon</item>
    <item name="android:windowSplashScreenBackground">?windowSplashScreenBackground</item>
    <item name="android:windowSplashScreenAnimationDuration"> ?windowSplashScreenAnimationDuration</item>
</style>

2. 打造进场效果

在原有的Demo上适配新的API,感觉缺乏新意。之前用Jetpack Compose复刻的Flappy Bird游戏没来得及设计启动画面,那这次就利用Jetpack的SplashScreen库完善一下。

2.1 准备动画图标

Flappy Bird游戏的Logo是一个小鸟,目前只有一张PNG,要定制Icon动画效果的话要转为SVG。

1832b220aa754cd18c504acc7686a560.png

找了很多工具,终于发现一个可以将PNG完美转换为SVG的网站:支持添加和删除各种颜色区域,进而可以最大程度地还原每个色块,每个Path。

https://www.pngtosvg.com/

1832b220aa754cd18c504acc7686a560.png

通过AS自带的Vector Asset ToolAnimated Vector Drawable标签,可以将SVG扩展成格式效果的矢量图动画文件。

<animated-vector ...>
    <aapt:attr name="android:drawable">
        <vector
            android:width="400dp"
            android:height="404.73373dp"
            ...>
            <group
                android:name="BirdGroup"
                android:pivotX="200"
                android:pivotY="202"
                android:rotation="0">
                <path
                    android:fillColor="#503745"
                    android:fillType="evenOdd"
                    android:pathData="M173.7,133.065C173.419,133.178 ..."
                    android:strokeColor="#00000000" />
                ...
            </group>
        </vector>
    </aapt:attr>
  <target android:name="BirdGroup">
    <aapt:attr name="android:animation">
      <set>
        <objectAnimator
            android:duration="@integer/icon_animator_duration"
            android:interpolator="@android:anim/decelerate_interpolator"
            android:propertyName="translateX"
            android:valueFrom="@integer/icon_animator_translate_from"
            android:valueTo="@integer/icon_animator_translate_to" />
        ...
      </set>
    </aapt:attr>
  </target>
</animated-vector>

2.2 适配主题

Android 12上给入口Activity指定Splash Screen功能的相关属性就可以实现进场效果。SplashScreen库也是一样的思路,不过为了简化代码,我们可以给Activity配置库预设好的主题。


因App端要给这些属性指定独有的资源,所以主题还需要简单扩展下,同时也要针对版本进行区分。如果碰巧最早也支持到Android 6的话,配置默认主题和面向12的values-v31主题即可,不然还需要配置面向6~11的values-23主题。


默认主题必须继扩展自预设主题Theme.SplashScreen,同时覆写一下Icon、Duration和ScreenBackground三个属性。因面向12的主题的部分属性和默认主题是一致的,所以将共通的部分抽出到Base中复用。

<style name="JetpackSplashTheme" parent="JetpackSplashTheme.Base">
</style>
<style name="JetpackSplashTheme.Base" parent="Theme.SplashScreen">
    ...
    <item name="windowSplashScreenAnimatedIcon">@drawable/ic_icon_bird_small_animated_translate</item>
    <item name="windowSplashScreenAnimationDuration">@integer/icon_animator_duration</item>
    <item name="windowSplashScreenBackground">@color/appBackground</item>
    <item name="postSplashScreenTheme">@style/SplashActivityTheme</item>
</style>
<style name="SplashActivityTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar">
    <item name="colorPrimary">@color/purple_500</item>
    <item name="colorPrimaryDark">@color/purple_700</item>
    <item name="colorAccent">@color/teal_200</item>
</style>

需要提醒的是,最好指定下postSplashScreenTheme属性。因为后续的定制效果需要用到SplashScreen类,而它将严格检查要求这个属性的配置,否则会发生Crash。


Cannot set AppTheme. No theme value defined for attribute postSplashScreenTheme.


另外,大部分Activity一般继承自AppCompat框架提供的Activity,该框架要求画面必须配置AppCompat系主题。也就是说,postSplashScreenTheme属性不仅要指定,还得是AppCompat系主题!


备注:AppCompat框架作此限制的原因,可以在之前写的文章里查看「深度解读Jetpack框架的基石-AppCompat」。


You need to use a Theme.AppCompat theme!


通过复用共通主题,面向12的主题只需要指定Icon背景属性IconBackgroundColor和品牌Logo属性BrandingImage。

<style name="JetpackSplashTheme" parent="JetpackSplashTheme.Base">
    <item name="android:windowSplashScreenIconBackgroundColor">@color/skyBlue</item>
    <item name="android:windowSplashScreenBrandingImage">@drawable/ic_tm_brand_newer</item>
</style>

下面是分别运行在Android 8.1和12上的启动画面进场效果,小鸟从左边入场并逐渐放大的动画。

image.gif

再比如小鸟旋转着放大进场动画。

image.gif

事实上Animated Vector Drawable所支持的Path动画更加炫酷和灵活,可以打造更丰富的动画体验,大家可以试试!

2.3 优化低版本的进场Icon

通过对比,可以看到8.1的进场效果里确实没有展示Icon动画,也没有Icon背景和品牌Logo。为了尽可能和12的进场效果接近,可以将低版本主题的图标属性改为Adaptive Icon,面向12的主题才使用动画Icon。

<!-- 默认主题:面向12之前的版本 -->
<style name="JetpackSplashTheme" parent="JetpackSplashTheme.Base">
    <!-- Adaptive icon drawable -->
    <item name="windowSplashScreenAnimatedIcon">@mipmap/ic_launcher_bird_final</item>
</style>
<!-- 面向12的版本 -->
<style name="JetpackSplashTheme" parent="JetpackSplashTheme.Base">
    <!-- Animated vector drawable -->
    <item name="windowSplashScreenAnimatedIcon">@drawable/ic_icon_bird_small_animated_translate</item>
    ...
</style>

2Zmh5D.gif

3. 延长启动画面

3.1 获取SplashScreen定制入口

上述主题配置完就可以实现进场效果了,但为了进一步控制启动画面或定制退场效果,还得取得控制的入口即SplashScreen类。SplashScreen库提供的是installSplashScreen()

class MainActivity : ComponentActivity() {
    private val viewModel: GameViewModel by viewModels()
    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        // Need to be called before setContentView or other view operation on the root view.
        val splashScreen = installSplashScreen()
        setContent { ... }
        SplashScreenController(splashScreen, viewModel).apply {
            customizeSplashScreen()
        }
    }
}

有一点需要留意一下:installSplashScreen()必须先于setContentView()调用,原因在于install函数会获取postSplashScreenTheme属性指定的主题,并在检查通过后setTheme给Activity。


需要明确一下:install函数只是执行一下主题和资源方面的初始化,此刻尚未加载退场使用的视图。

3.2 控制启动画面展示时长

当App的第一帧开始描画,启动画面Window即Splash Screen Window将退出。若描画已经开始,但部分关键逻辑还没执行完,这将影响完整的展示。这时候我们可以适当地延长启动画面,让用户再等一会儿。


Android 12并没有提供控制启动时长的API,之前的Demo是通过向ContentView注册OnPreDrawListener回调挂起描画来实现的。(挂起描画间接导致Splash Screen Window的延迟退出,进而达到延长启动画面的目的。)


SplashScreen库提供了专用API来处理这种需求,即KeepOnScreenCondition。我们需要告知SplashScreen需要持续展示的条件,在条件被破坏之前WMS将维持它的展示。事实上这个API的实现原理跟之前的思路是一致的。

class SplashScreenController( ... ) {
    fun customizeSplashScreen() {
        keepSplashScreenLonger()
        ...
    }
    // Keep splash screen showing till data initialized.
    private fun keepSplashScreenLonger() {
        splashScreen.setKeepVisibleCondition { !viewModel.isDataReady() }
    }
}

可以看到启动画面的展示时间明显变长了。

2Zmh5D.gif




相关文章
|
7月前
|
存储 安全 Android开发
构建高效的Android应用:Kotlin与Jetpack的结合
【5月更文挑战第31天】 在移动开发的世界中,Android 平台因其开放性和广泛的用户基础而备受开发者青睐。随着技术的进步和用户需求的不断升级,开发一个高效、流畅且易于维护的 Android 应用变得愈发重要。本文将探讨如何通过结合现代编程语言 Kotlin 和 Android Jetpack 组件来提升 Android 应用的性能和可维护性。我们将深入分析 Kotlin 语言的优势,探索 Jetpack 组件的核心功能,并通过实例演示如何在实际项目中应用这些技术。
|
7月前
|
Java 数据库 Android开发
构建高效Android应用:Kotlin与Jetpack的完美结合
【5月更文挑战第28天】 在现代移动开发领域,Android平台以其广泛的用户基础和开放性受到开发者青睐。随着技术的不断进步,Kotlin语言以其简洁性和功能性成为Android开发的首选。而Android Jetpack组件则为开发者提供了一套高质量的设计架构、工具和UI组件,以简化应用程序的开发过程。本文将探讨如何利用Kotlin语言和Android Jetpack组件共同构建一个高效的Android应用程序,涵盖从语言特性到架构模式的全面分析,并提供具体的实践指导。
|
7月前
|
XML Java Android开发
安卓开发新趋势:Jetpack Compose的兴起与应用
【5月更文挑战第25天】随着移动开发技术的不断演进,安卓平台的创新也在持续推进。近年来,一个名为Jetpack Compose的新工具集引起了开发者社区的广泛关注。本文将深入探讨Jetpack Compose的核心概念、优势以及它对现有安卓开发模式的影响,并分析其在实际项目中的应用潜力。
|
7月前
|
安全 数据库 Android开发
构建高效Android应用:采用Kotlin与Jetpack的实践指南
【5月更文挑战第22天】 在移动开发领域,Android系统因其开放性和广泛的用户基础而备受开发者青睐。随着技术的不断演进,Kotlin语言以其简洁性和功能性成为Android开发的首选语言。本文将深入探讨如何结合Kotlin和Android Jetpack组件来构建一个高效且易于维护的Android应用。我们将重点讨论如何使用Jetpack的核心组件,如LiveData、ViewModel和Room,以及Kotlin的语言特性来优化代码结构,提高应用性能,并简化数据管理。通过具体案例分析,本文旨在为开发者提供一套实用的技术指导,帮助他们在竞争激烈的市场中脱颖而出。
|
7月前
|
物联网 区块链 Android开发
构建高效Android应用:Kotlin与Jetpack的实践之路未来技术的融合潮流:区块链、物联网与虚拟现实的交汇点
【5月更文挑战第30天】 在移动开发领域,效率和性能始终是开发者追求的核心。随着技术的不断进步,Kotlin语言以其简洁性和现代化特性成为Android开发的新宠。与此同时,Jetpack组件为应用开发提供了一套经过实践检验的库、工具和指南,旨在简化复杂任务并帮助提高应用质量。本文将深入探索如何通过Kotlin结合Jetpack组件来构建一个既高效又稳定的Android应用,并分享在此过程中的最佳实践和常见陷阱。
|
7月前
|
安全 Java Android开发
构建高效Android应用:Kotlin与Jetpack实践指南
【5月更文挑战第29天】 在移动开发的世界中,效率和性能始终是核心诉求。随着技术的演进,Kotlin语言以其简洁性和功能性成为Android开发的首选。结合Jetpack组件的推广,开发者得以构建更高效、可维护且易于测试的应用。本文将深入探讨利用Kotlin语言特性以及Jetpack架构组件来优化Android应用的策略和技巧,旨在帮助开发者提升应用质量并降低维护成本。
|
7月前
|
持续交付 Android开发 开发者
构建高性能微服务架构:后端开发的终极指南构建高效Android应用:Kotlin与Jetpack的完美结合
【5月更文挑战第28天】 在现代软件开发的浪潮中,微服务架构已经成为了设计灵活、可扩展且易于维护系统的重要模式。本文将深入探讨如何构建一个高性能的微服务架构,涵盖从基础概念理解到实践策略部署的全过程。我们将讨论关键的设计原则、技术选型、性能优化技巧以及安全性考虑,旨在为后端开发者提供一个全面的指南,帮助他们构建出能够适应快速变化的市场需求和技术挑战的系统。 【5月更文挑战第28天】 在移动开发的世界中,效率和性能是衡量一个应用成功与否的关键因素。本文将深入探讨如何通过结合Kotlin语言和Android Jetpack组件,来构建一个既高效又易维护的Android应用。我们将透过实际案例分析
|
7月前
|
安全 测试技术 Android开发
构建高效Android应用:Kotlin与Jetpack的实践指南
【5月更文挑战第27天】 在移动开发的世界中,效率和性能是衡量一个应用成功与否的关键因素。对于Android开发者来说,Kotlin语言和Jetpack组件套件的出现,不仅优化了开发流程,还提升了应用的性能和稳定性。本文将深入探讨如何通过Kotlin语言结合Jetpack组件,构建出既高效又稳定的Android应用。我们将从语言特性、架构组件到实际开发案例,一步步解析Kotlin和Jetpack的协同作用,帮助开发者打造出更优质的应用体验。
|
7月前
|
安全 Java Android开发
构建高效Android应用:Kotlin与Jetpack的实践指南
【5月更文挑战第20天】 在移动开发的世界中,效率和性能始终是开发者追求的核心目标。随着技术的不断进步,Kotlin语言以其简洁、安全和实用的特性成为了Android开发的首选语言。与此同时,Android Jetpack组件的推出,为开发者提供了一套高质量的库、工具和指南,以简化应用程序的开发过程。本文将探讨如何结合Kotlin语言和Jetpack组件来构建一个高效的Android应用,涵盖从项目初始化到性能优化的全过程。
|
7月前
|
Android开发
Android Jetpack架构开发组件化应用实战,字节跳动+阿里+华为+腾讯等大厂Android面试题
Android Jetpack架构开发组件化应用实战,字节跳动+阿里+华为+腾讯等大厂Android面试题