Android 12上全新的应用启动画面,适配一下? - 程序师

文章推薦指數: 80 %
投票人數:10人

早期的Android上App的启动速度常为人诟病,如今的启动表现已不逊iOS。

Google针对系统的不断优化绝对功不可没,从8.0独立出来的SplashWindow,到12上推出的 ... 早期的Android上App的启动速度常为人诟病,如今的启动表现已不逊iOS。

Google针对系统的不断优化绝对功不可没,从8.0独立出来的SplashWindow,到12上推出的全新SplashScreen。

在App的主要内容展示之前,按照需求的不同,或多或少会先展示这样几个画面。

画面 用途 SplashScreen 展示品牌Logo或Slogan AdvertisementScreen 展示节日活动或日常广告 GuideScreen 演示重点功能,一般只展示一次 启动过程示意图 1前言 我们常常花费精力去打造引导画面或广告画面,而作为第一印象的启动画面却容易被忽视。

回想下以前都是怎么处理这个画面的: 一般通过设置windowSplashscreenContent属性来展示UI提供的启动图,系统将为它创建专门的Window 假使忘记设置这个属性的话,默认的白色背景将导致启动过程中会有个白画面一闪而过 要去掉这个突兀的白画面可不能简单地设置Background为null,不然一闪而过的又会变成黑画面 最终发现windowDisablePreview属性可以彻底关闭这个画面,这样一来确实没有任何突兀的画面一闪而过了 但这又会带来启动”变慢”的副作用,因为用来过渡的启动画面被关闭之后,App描画前屏幕几乎没有什么变化。

即便App性能没有劣化,但为了留住用户,我们还是得好好对待这个启动画面。

然而现有的windowSplashscreenContent可供定制的空间着实有限。

也许官方也注意到了这点,便精心设计了SplashScreen API,并在Android12里重磅推出。

有了这个全新特性的帮助,启动画面的定制将更加自由、方便。

先来看下采用SplashScreenAPI快速定制的启动效果。

下面将逐步演示全新SplashScreen可供定制的各个方面。

2定制进入效果 采用xml即可快速定制各式进入效果。

2.1默认的启动效果 默认情况下启动画面将展示白色背景和Launcher上的AdaptiveIcon,也是不错的,比以前的白画面好很多。

2.2自定义静态Icon 替换Icon为AdaptiveIcon的前景图,背景色微调为米黄色。

@color/newSplashScreenColor @drawable/ic_kotlin_hero_new 2.3自定义Icon背景 Icon色调和画面背景色的对比不够明显的情况下,可以添加Icon背景色加强辨识度。

@color/newSplashIconMaskColor 2.4自定义品牌Logo 添加品牌Logo可以展示企业形象或Slogan,使得启动画面更为完整和精细。

@drawable/ic_tm_brand_newer 2.5自定义动画Icon 动画Icon可以增添设计和创意,使得启动流程更加流畅和有趣。

@drawable/ic_kotlin_hero_new_animated_rotate @integer/icon_animator_duration 比如让机器人图标旋转起来。

再比如让机器人在Kotlin上侧滑。

或者让几何图案拼凑出字母K之后和机器人汇合,象征着Android和Kotlin的强强联合。

注意: 动画Icon的时长上限为1000ms。

图标的进入动画可以定制,但由系统控制,不可以被监听和额外处理。

2.6延长启动画面 Thesplashscreenisdismissedassoonasyourappdrawsitsfirstframe.Ifyouneedtoloadasmallamountofdatasuchasin-appthemesettingsfromalocaldiskasynchronously,youcanuseViewTreeObserver.OnPreDrawListenertosuspendtheapptodrawitsfirstframe. 后台数据的加载难免耗时,启动画面结束了主要内容仍未加载好的话,体验不是太好。

能够控制启动画面的持续时时长就好了。

现有的ViewTreeObserver的OnPreDrawListener回调是可以挂起描画的,如果我们在数据准备好之后再放行描画,就可以间接地延长启动画面的显示。

比如Activity初始化2s后才放行描画。

class SplashActivity : AppCompatActivity() {     override fun onCreate(savedInstanceState: Bundle?) {         ...         keepSplashScreenLonger()     }     private fun keepSplashScreenLonger() {         // 监听Content View的描画时机         val content: View = findViewById(android.R.id.content)         content.viewTreeObserver.addOnPreDrawListener(             object : ViewTreeObserver.OnPreDrawListener {                 override fun onPreDraw(): Boolean {                     // 准备好了描画放行,反之挂起                     return if (viewModel.isDataReady()) {                         content.viewTreeObserver.removeOnPreDrawListener(this)                         true                     } else {                         false                     }                 }             }         )     } } class MyViewModel(application: Application): AndroidViewModel(application) {     companion object {         const val WORK_DURATION = 2000L     }     private val initTime = SystemClock.uptimeMillis()     fun isDataReady() = SystemClock.uptimeMillis() - initTime > WORK_DURATION } 看一下效果,发现启动画面的展示时间确实变长了。

3定制退出效果 当App的第一帧开始描画,SplashScreen将会退出展示。

为了丰富退出环节的体验,系统也开放了相应的入口,即画面退出的回调。

在这个回调里可以开始退出效果的定制,包括整体的退出动画和图标的退出动画。

3.1监听启动画面的退出 向SplashScreen注册OnExitAnimationListener接口即可监听启动画面的退出。

override fun onCreate(savedInstanceState: Bundle?) {     ...     customizeSplashScreenExit() } private fun customizeSplashScreenExit() {     splashScreen.setOnExitAnimationListener { splashScreenView ->         Log.d("Splash", "SplashScreen#onSplashScreenExit view:$splashScreenView")         sleep(1000)         Log.d("Splash", "SplashScreen#remove after sleeping")         splashScreenView.remove()     } } 可以看到启动画面展示之后,不作定制的默认情况下就是全屏一下再消失。

日志如下: Splash  : Activity:com.example.splash.MainActivity@f70c0d0 Activity:com.example.splash.MainActivity@f70c0d0 onCreate Splash  : Activity:com.example.splash.MainActivity@f70c0d0 onStart Splash  : Activity:com.example.splash.MainActivity@f70c0d0 onResume Splash  : SplashScreen#onSplashScreenExit view:android.window.SplashScreenView{18339d5 V.E...... ........ 0,0-1080,2280} Splash  : SplashScreen#remove after sleeping 一定记得调用remove及时移除启动画面,否则SplashScreen会长时间盖在主画面上,大概在5s左右。

另外,回调的注册需要放在Activity#onResume前,不然监听不到。

3.2定制整体的退出动画 可以给启动画面的整体设置TRANSLATE、SCALE、ROTATE、ALPHA等各种动画,使得退出更加自然。

比如给SplashScreen加上一个缩小出屏幕的动画。

private fun customizeSplashScreenExit() {     splashScreen.setOnExitAnimationListener { splashScreenView ->         showSplashExitAnimator(splashScreenView)     } } private fun showSplashExitAnimator(splashScreenView: SplashScreenView) {     val path = Path()     path.moveTo(1.0f, 1.0f)     path.lineTo(0f, 0f)     val scaleOut = ObjectAnimator.ofFloat(         splashScreenView,         View.SCALE_X,         View.SCALE_Y,         path     )     ...     scaleOut.doOnEnd {         splashScreenView.remove()     }     scaleOut.start() } 又或者从上方平移出屏幕的动画。

private fun showSplashExitAnimator(splashScreenView: SplashScreenView) {     val slideUp = ObjectAnimator.ofFloat(         splashScreenView,         View.TRANSLATION_Y,         0f,         -splashScreenView.height.toFloat()     )     ...     slideUp.start() } 3.3定制图标的退出动画 当然也可以给图标单独加上动画,比如将Icon上滑。

private fun customizeSplashScreenExit() {     splashScreen.setOnExitAnimationListener { splashScreenView ->         showSplashIconExitAnimator(splashScreenView)     } } private fun showSplashIconExitAnimator(splashScreenView: SplashScreenView) {     val iconView = splashScreenView.iconView ?: return     val slideUp = ObjectAnimator.ofFloat(         splashScreenView.iconView,         View.TRANSLATION_Y,         0f,         -iconView.height * 2.toFloat()     )     ...     slideUp.start() } 3.4退出动画的适当时长 针对退出动画的定制官方还有一段补充说明。

Bythestartofthiscallback,theanimatedvectordrawableonthesplashscreenhasbegun.Dependingonthedurationoftheapplaunch,thedrawablemightbeinthemiddleofitsanimation.UseSplashScreenView.getIconAnimationStarttoknowwhentheanimationstarted.Youcancalculatetheremainingdurationoftheiconanimation. 简言之,退出画面回调的时候Icon动画可能进行到了一半,最好计算Icon动画的剩余时长来执行退出动画。

原因在于设备性能会影响App描画的早晚,而第一帧描画的时候上述的退出回调将被执行。

也就是说,性能的优劣会影响启动画面退出的回调时机。

性能好的话,画面退出的回调较早。

此时Icon动画尚在进行当中,可以将Icon动画的预设时长的剩余时间交接给退出效果来执行 性能差的话,画面退出的回调稍晚。

Icon动画早已经结束,为了让用户尽早看到画面内容,就不该再执行退出效果了而是直接退出 不能为了展示效果而让用户久等,否则会弄巧成拙。

借助SplashScreenView的iconAnimationStartMillis和iconAnimationDurationMillis方法可以推算出Icon动画的剩余时长。

*模拟器上运行的缘故,大部分时候我的Demo在启动画面退出的时候Icon动画都结束了,少部分情况下动画还剩余一点时间,可能实机的情况会不一样。

private fun showSplashIconExitAnimator(splashScreenView: SplashScreenView) {     slideUp.duration = getRemainingDuration(splashScreenView)     ... } fun getRemainingDuration(splashScreenView: SplashScreenView): Long  {     // 取得Icon动画的时长     val animationDuration = splashScreenView.iconAnimationDurationMillis     // 取得Icon动画的开始时刻     val animationStart = splashScreenView.iconAnimationStartMillis     // 再结合当前时间计算出Icon动画的剩余时长     // 1. 时长为负则固定为0ms即直接退出     // 2. 时长为正则采用该时长执行退出动画     return if (animationDuration != null && animationStart != null) {         (animationDuration - SystemClock.uptimeMillis() + animationStart)         .coerceAtLeast(0L)     } else {         0L     } } 4SplashScreen相关API 4.1类和接口 类/接口 作用 SplashScreen 启动画面管理接口,通过Activity#getSplashScreen取得 OnExitAnimationListener 启动画面退出的回调接口,通过SplashScreen#setOnExitAnimationListener注册 SplashScreenView 启动画面包含的视图,用以定制整体或Icon的退出动画 4.2属性 attr 作用 备注 splashScreenTheme 指定SplashScreen相关的Style 存在一点显示问题 windowSplashScreenBackground 启动画面的背景颜色 默认读取Background windowSplashScreenBrandingImage 指定启动画面底部的品牌Logo – windowSplashScreenAnimatedIcon 指定Icon,支持静态或动画Drawable – windowSplashScreenAnimationDuration 指定动画Icon时长 上限1000ms windowSplashScreenIconBackgroundColor 补充Icon背景 – 注意:windowSplashscreenContent是8.0版本新增的定制启动画面的属性,自12开始废弃了,使用windowSplashscreenAnimatedIcon替代 4.3SplashScreen的构成 启动画面构成图 5注意 需要尝鲜SplashScreen的话,需要在Android12上开发,并做如下必要配置。

compileSdkVersion和targetSdkVersion声明为S android:exported="true",明示声明启动画面的可见性,否则会安装失败 另外启动页的Icon无论是静态的还是动画效果的,都应遵循AdaptiveIcon的规范,不然Icon会发生变形。

6结语 Android12上全新的SplashScreenAPI非常简单清晰,整个定制过程非常流畅! 相信在全新的API加持下,APP的启动画面可以迸发出更多特色的、好玩的创意。

快快尝试起来,给你的用户留下第一眼的好印象~ 本文DEMO https://github.com/ellisonchan/SplashScreen 参考资料 https://developer.android.google.cn/about/versions/12/features/splash-screen https://developer.android.google.cn/reference/android/window/SplashScreen 本文文字及图片出自微信公众号 余下全文(1/3) 分享这篇文章: 相关文章: 在谷歌刚发布的安卓13里,我又找到了华为的技术。





为啥小米开发者提交了两行代码就被网友喷了? 小米提议禁止安卓手机提取APK文件,遭谷歌驳回 最新一代安卓系统来了!安卓12新特性详细解析 谷歌正式发布Android12:可谁又在乎呢? “反安卓”联盟往事 在安卓项目里部署so文件你需要知道的知识 谷歌收购Android图形驱动测试公司GraphicsFuzz 谷歌为什么要对Android的开源严防死守? 若欧盟真重罚谷歌50亿美元Android将会发生这些改变 你的反应是: 0 俺的神呀0 赞一个0 飘过~0 强0 很实用0 好文0 笑死了0 mark0 敬佩0 垃圾0 0 看样子你已经点过这个了! 抱歉,你最多只能点三个! 请关注我们: 文章导航 上一文章谷歌要用SoC代替主板了吗?下一文章Python之父:让Python快2倍 发表评论取消回复 邮箱地址不会被公开。

必填项已用*标注评论名称* 站点 电子邮件* 益智游戏 趣味益智互动游戏:请画一个小人! 趣味益智互动游戏:请画一个小人! 益智游戏 测试:你的眼睛对颜色敏感吗?!测一测你能得多少分。

你的眼睛对颜色敏感吗?!测一测你能得多少分。

业界观察 LinusTorvalds:我不再了解编程,不再是一名程序员了 Torvalds解释说,他不再了解编码了,目前写的大多数代码都在电子邮件中。

每当有人发送了补丁,他就用伪代码回复 业界观察 如果阿里月饼黑客事件发生在谷歌会怎样?前Google人亲述他抢了50件T-shirt的故事 本文作者吴卓浩,前Google中国用户体验团队负责人。

业界观察 搞笑视频:JavaScript才是真正的老大 《掌掴》JavaScript篇 业界观察 雷军22年前写的代码你见过吗? 网上出现一篇“刘强东的代码水平如何”的文章,有网友在下面回复“代码只服雷军”。

这个回复吸引了小编的注意,雷军的代码水平真的很牛吗? 业界观察 趣图:想搞机器学习,数学总是障碍 这是机器学习和数学的关系 编程技术 javascript中的错误处理 这是关于JavaScript中异常处理的故事。

如果你相信墨菲定律,那么任何事情都可能出错,不,一定会出错!这篇文章中我们来看下JavaScript中的出错处理。

文章会覆盖异常处理使用的正反例,然后看下ajax的异步处理。

业界观察 为什么是Go而不是Rust Rust是一个更好的C++,即使你偶尔听到有人说Go是一个更好的C,但事实并非如此。

任何带有内置垃圾收集器和运行时的语言,都不能被视为C语言。

别搞错了,Rust才是C++,而不是C。

业界观察 2019年谁在寻找Docker职位,谁又在雇佣Docker职员? 人均年薪80万以上,50%的职位空缺,Docker入坑不亏? 业界观察 每个程序员都需要掌握的30件事 从事编程并不容易。

每年有许多人从各国的顶级计算机科学专业毕业,这是所有人都向往的有竞争力的职业之一。

与此同时,编程也振奋人心。

随着技术的进步,每天都有新的创新。

对于喜欢编程,并立志从事编程的人而言,编程是其热爱且为之奋斗的事业。

程序人生 要嫁就嫁程序猿——钱多话少死的早 我是一个苦b的程序员,今晚加班到快通宵了,困得快睁不开眼了,女上司很关心,问我要不要吃宵夜。

我没好气地说,宵夜就算了,能让我睡一觉就行了。

女上司红着脸说了句讨厌 × 感谢你的参与互动。

姓名* 电子邮件* 输入有误!



請為這篇文章評分?