<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Android 12:全新的App啟動(dòng)動(dòng)畫!

          共 8185字,需瀏覽 17分鐘

           ·

          2021-10-28 23:54

          ?BATcoder技術(shù)群,讓一部分人先進(jìn)大廠

          大家,我是劉望舒,騰訊TVP,著有三本業(yè)內(nèi)知名暢銷書,連續(xù)四年蟬聯(lián)電子工業(yè)出版社年度優(yōu)秀作者,百度百科收錄的資深技術(shù)專家。

          前華為架構(gòu)師,現(xiàn)大廠技術(shù)總監(jiān)。


          想要加入?BATcoder技術(shù)群,公號(hào)回復(fù)BAT?即可。

          早期的Android上App的啟動(dòng)速度常為人詬病,如今的啟動(dòng)表現(xiàn)已不遜iOS。Google針對(duì)系統(tǒng)的不斷優(yōu)化絕對(duì)功不可沒,從8.0獨(dú)立出來的SplashWindow,到12上推出的全新SplashScreen

          在App的主要內(nèi)容展示之前,按照需求的不同,或多或少會(huì)先展示這樣幾個(gè)畫面。

          畫面用途
          Splash Screen展示品牌Logo或Slogan
          Advertisement Screen展示節(jié)日活動(dòng)或日常廣告
          Guide Screen演示重點(diǎn)功能,一般只展示一次
          6522a621954e4c274af48628a8471da0.webp啟動(dòng)過程示意圖

          1 前言

          我們常常花費(fèi)精力去打造引導(dǎo)畫面或廣告畫面,而作為第一印象的啟動(dòng)畫面卻容易被忽視?;叵胂乱郧岸际窃趺刺幚磉@個(gè)畫面的:

          1. 一般通過設(shè)置windowSplashscreenContent屬性來展示UI提供的啟動(dòng)圖,系統(tǒng)將為它創(chuàng)建專門的Window

          2. 假使忘記設(shè)置這個(gè)屬性的話,默認(rèn)的白色背景將導(dǎo)致啟動(dòng)過程中會(huì)有個(gè)白畫面一閃而過

          3. 要去掉這個(gè)突兀的白畫面可不能簡(jiǎn)單地設(shè)置Background為null,不然一閃而過的又會(huì)變成黑畫面

          4. 最終發(fā)現(xiàn)windowDisablePreview屬性可以徹底關(guān)閉這個(gè)畫面,這樣一來確實(shí)沒有任何突兀的畫面一閃而過了

          但這又會(huì)帶來啟動(dòng)"變慢"的副作用,因?yàn)橛脕磉^渡的啟動(dòng)畫面被關(guān)閉之后,App描畫前屏幕幾乎沒有什么變化。即便App性能沒有劣化,但為了留住用戶,我們還是得好好對(duì)待這個(gè)啟動(dòng)畫面。

          然而現(xiàn)有的windowSplashscreenContent可供定制的空間著實(shí)有限。也許官方也注意到了這點(diǎn),便精心設(shè)計(jì)了Splash Screen ?API,并在Android 12里重磅推出。

          有了這個(gè)全新特性的幫助,啟動(dòng)畫面的定制將更加自由、方便。先來看下采用SplashScreen API 快速定制的啟動(dòng)效果。

          ab7e912d57136cfbf51dd87e143aebee.webp

          下面將逐步演示全新SplashScreen可供定制的各個(gè)方面。

          2 定制進(jìn)入效果

          采用xml即可快速定制各式進(jìn)入效果。

          2.1 默認(rèn)的啟動(dòng)效果

          默認(rèn)情況下啟動(dòng)畫面將展示白色背景和Launcher上的Adaptive Icon,也是不錯(cuò)的,比以前的白畫面好很多。

          748043a7159202221f94b4b5ca4a0030.webp

          2.2 自定義靜態(tài)Icon

          替換Icon為Adaptive Icon的前景圖,背景色微調(diào)為米黃色。

          <item?name="android:windowSplashScreenBackground">@color/newSplashScreenColoritem>
          <item?name="android:windowSplashScreenAnimatableIcon">@drawable/ic_kotlin_hero_newitem>
          fd702ac48f6628f948eab080832ad690.webp

          2.3 自定義Icon背景

          Icon色調(diào)和畫面背景色的對(duì)比不夠明顯的情況下,可以添加Icon背景色加強(qiáng)辨識(shí)度。

          <item?name=”android:windowSplashScreenIconBackground”>@color/newSplashIconMaskColoritem>
          d92656a35c22eae4044c2d206fed829b.webp

          2.4 自定義品牌Logo

          添加品牌Logo可以展示企業(yè)形象或Slogan,使得啟動(dòng)畫面更為完整和精細(xì)。

          <item?name=”android:windowSplashScreenBrandingImage”>@drawable/ic_tm_brand_neweritem>
          8c570b533c042fa97c6640f5c65f9c49.webp

          2.5 自定義動(dòng)畫Icon

          動(dòng)畫Icon可以增添設(shè)計(jì)和創(chuàng)意,使得啟動(dòng)流程更加流暢和有趣。

          <item?name="android:windowSplashScreenAnimatableIcon">@drawable/ic_kotlin_hero_new_animated_rotateitem>
          <item?name="android:windowSplashScreenAnimationDuration">@integer/icon_animator_durationitem>

          比如讓機(jī)器人圖標(biāo)旋轉(zhuǎn)起來。

          4617659ecc731b904771232ee4c28578.webp

          再比如讓機(jī)器人在Kotlin上側(cè)滑。

          6a2c076144a441a411e87eed98ec55ec.webp

          或者讓幾何圖案拼湊出字母K之后和機(jī)器人匯合,象征著AndroidKotlin的強(qiáng)強(qiáng)聯(lián)合。

          0890aa379a9f42871740d1c9c0b1c2ad.webp

          注意:

          • 動(dòng)畫Icon的時(shí)長上限為1000ms
          • 圖標(biāo)的進(jìn)入動(dòng)畫可以定制,但由系統(tǒng)控制,不可以被監(jiān)聽和額外處理。

          2.6 延長啟動(dòng)畫面

          The splash screen is dismissed as soon as your app draws its first frame. If you need to load a small amount of data such as in-app theme settings from a local disk asynchronously, you can use ViewTreeObserver.OnPreDrawListener to suspend the app to draw its first frame.

          后臺(tái)數(shù)據(jù)的加載難免耗時(shí),啟動(dòng)畫面結(jié)束了主要內(nèi)容仍未加載好的話,體驗(yàn)不是太好。能夠控制啟動(dòng)畫面的持續(xù)時(shí)時(shí)長就好了。

          現(xiàn)有的ViewTreeObserver的OnPreDrawListener回調(diào)是可以掛起描畫的,如果我們?cè)跀?shù)據(jù)準(zhǔn)備好之后再放行描畫,就可以間接地延長啟動(dòng)畫面的顯示。

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

          class?SplashActivity?:?AppCompatActivity()?{
          ????override?fun?onCreate(savedInstanceState:?Bundle?)?{
          ????????...
          ????????keepSplashScreenLonger()
          ????}

          ????private?fun?keepSplashScreenLonger()?{
          ????????//?監(jiān)聽Content?View的描畫時(shí)機(jī)
          ????????val?content:?View?=?findViewById(android.R.id.content)
          ????????content.viewTreeObserver.addOnPreDrawListener(
          ????????????object?:?ViewTreeObserver.OnPreDrawListener?{
          ????????????????override?fun?onPreDraw():?Boolean?{
          ????????????????????//?準(zhǔn)備好了描畫放行,反之掛起
          ????????????????????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
          }

          看一下效果,發(fā)現(xiàn)啟動(dòng)畫面的展示時(shí)間確實(shí)變長了。

          24a0acaa37be365dd0aaa37433dcb829.webp

          3 定制退出效果

          當(dāng)App的第一幀開始描畫,SplashScreen將會(huì)退出展示。為了豐富退出環(huán)節(jié)的體驗(yàn),系統(tǒng)也開放了相應(yīng)的入口,即畫面退出的回調(diào)。在這個(gè)回調(diào)里可以開始退出效果的定制,包括整體的退出動(dòng)畫和圖標(biāo)的退出動(dòng)畫。

          3.1 監(jiān)聽啟動(dòng)畫面的退出

          向SplashScreen注冊(cè)O(shè)nExitAnimationListener接口即可監(jiān)聽啟動(dòng)畫面的退出。

          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()
          ????}
          }

          可以看到啟動(dòng)畫面展示之后,不作定制的默認(rèn)情況下就是全屏一下再消失。

          4e93c6647bde1616a9756cde4fb72ecb.webp

          日志如下:

          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

          一定記得調(diào)用remove及時(shí)移除啟動(dòng)畫面,否則SplashScreen會(huì)長時(shí)間蓋在主畫面上,大概在5s左右。

          另外,回調(diào)的注冊(cè)需要放在Activity#onResume前,不然監(jiān)聽不到。

          3.2 定制整體的退出動(dòng)畫

          可以給啟動(dòng)畫面的整體設(shè)置TRANSLATE、SCALE、ROTATE、ALPHA等各種動(dòng)畫,使得退出更加自然。

          比如給SplashScreen加上一個(gè)縮小出屏幕的動(dòng)畫。

          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()
          }
          53fa80d90e7ead42f64dabb4fdf5488d.webp

          又或者從上方平移出屏幕的動(dòng)畫。

          private?fun?showSplashExitAnimator(splashScreenView:?SplashScreenView)?{
          ????val?slideUp?=?ObjectAnimator.ofFloat(
          ????????splashScreenView,
          ????????View.TRANSLATION_Y,
          ????????0f,
          ????????-splashScreenView.height.toFloat()
          ????)
          ????...
          ????slideUp.start()
          }
          b450e349fc12919b77eb976ca2781cbd.webp

          3.3 定制圖標(biāo)的退出動(dòng)畫

          當(dāng)然也可以給圖標(biāo)單獨(dú)加上動(dòng)畫,比如將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()
          }
          65a2b4ccef23473d4e743516df1d6b23.webp

          3.4 退出動(dòng)畫的適當(dāng)時(shí)長

          針對(duì)退出動(dòng)畫的定制官方還有一段補(bǔ)充說明。

          By the start of this callback, the animated vector drawable on the splash screen has begun. Depending on the duration of the app launch, the drawable might be in the middle of its animation. Use SplashScreenView.getIconAnimationStart to know when the animation started. You can calculate the remaining duration of the icon animation.

          簡(jiǎn)言之,退出畫面回調(diào)的時(shí)候Icon動(dòng)畫可能進(jìn)行到了一半,最好計(jì)算Icon動(dòng)畫的剩余時(shí)長來執(zhí)行退出動(dòng)畫。

          原因在于設(shè)備性能會(huì)影響App描畫的早晚,而第一幀描畫的時(shí)候上述的退出回調(diào)將被執(zhí)行。也就是說,性能的優(yōu)劣會(huì)影響啟動(dòng)畫面退出的回調(diào)時(shí)機(jī)。

          • 性能好的話,畫面退出的回調(diào)較早。此時(shí)Icon動(dòng)畫尚在進(jìn)行當(dāng)中,可以將Icon動(dòng)畫的預(yù)設(shè)時(shí)長的剩余時(shí)間交接給退出效果來執(zhí)行
          • 性能差的話,畫面退出的回調(diào)稍晚。Icon動(dòng)畫早已經(jīng)結(jié)束,為了讓用戶盡早看到畫面內(nèi)容,就不該再執(zhí)行退出效果了而是直接退出

          不能為了展示效果而讓用戶久等,否則會(huì)弄巧成拙。

          借助SplashScreenView的iconAnimationStartMillisiconAnimationDurationMillis方法可以推算出Icon動(dòng)畫的剩余時(shí)長。

          * 模擬器上運(yùn)行的緣故,大部分時(shí)候我的Demo在啟動(dòng)畫面退出的時(shí)候Icon動(dòng)畫都結(jié)束了,少部分情況下動(dòng)畫還剩余一點(diǎn)時(shí)間,可能實(shí)機(jī)的情況會(huì)不一樣。

          private?fun?showSplashIconExitAnimator(splashScreenView:?SplashScreenView)?{
          ????slideUp.duration?=?getRemainingDuration(splashScreenView)
          ????...
          }

          fun?getRemainingDuration(splashScreenView:?SplashScreenView):?Long??{
          ????//?取得Icon動(dòng)畫的時(shí)長
          ????val?animationDuration?=?splashScreenView.iconAnimationDurationMillis
          ????//?取得Icon動(dòng)畫的開始時(shí)刻
          ????val?animationStart?=?splashScreenView.iconAnimationStartMillis

          ????//?再結(jié)合當(dāng)前時(shí)間計(jì)算出Icon動(dòng)畫的剩余時(shí)長
          ????//?1.?時(shí)長為負(fù)則固定為0ms即直接退出
          ????//?2.?時(shí)長為正則采用該時(shí)長執(zhí)行退出動(dòng)畫
          ????return?if?(animationDuration?!=?null?&&?animationStart?!=?null)?{
          ????????(animationDuration?-?SystemClock.uptimeMillis()?+?animationStart)
          ????????.coerceAtLeast(0L)
          ????}?else?{
          ????????0L
          ????}
          }

          4 SplashScreen相關(guān)API

          4.1 類和接口

          類/接口作用
          SplashScreen啟動(dòng)畫面管理接口,通過Activity#getSplashScreen取得
          OnExitAnimationListener啟動(dòng)畫面退出的回調(diào)接口,通過SplashScreen#setOnExitAnimationListener注冊(cè)
          SplashScreenView啟動(dòng)畫面包含的視圖,用以定制整體或Icon的退出動(dòng)畫

          4.2 屬性

          attr作用備注
          splashScreenTheme指定SplashScreen相關(guān)的Style存在一點(diǎn)顯示問題
          windowSplashScreenBackground啟動(dòng)畫面的背景顏色默認(rèn)讀取Background
          windowSplashScreenBrandingImage指定啟動(dòng)畫面底部的品牌Logo-
          windowSplashScreenAnimatedIcon指定Icon,支持靜態(tài)或動(dòng)畫Drawable-
          windowSplashScreenAnimationDuration指定動(dòng)畫Icon時(shí)長上限1000ms
          windowSplashScreenIconBackgroundColor補(bǔ)充Icon背景-

          注意:windowSplashscreenContent是8.0版本新增的定制啟動(dòng)畫面的屬性,自12開始廢棄了,使用windowSplashscreenAnimatedIcon替代

          4.3 SplashScreen的構(gòu)成

          7dfc45685f8afcc982b7dcc55465701d.webp

          啟動(dòng)畫面構(gòu)成圖

          5 注意

          需要嘗鮮SplashScreen的話,需要在Android 12上開發(fā),并做如下必要配置。

          • compileSdkVersion和targetSdkVersion聲明為S

          • android:exported="true",明示聲明啟動(dòng)畫面的可見性,否則會(huì)安裝失敗

          另外啟動(dòng)頁的Icon無論是靜態(tài)的還是動(dòng)畫效果的,都應(yīng)遵循Adaptive Icon的規(guī)范,不然Icon會(huì)發(fā)生變形。

          6 結(jié)語

          Android 12上全新的SplashScreen API非常簡(jiǎn)單清晰,整個(gè)定制過程非常流暢!

          相信在全新的API加持下,APP的啟動(dòng)畫面可以迸發(fā)出更多特色的、好玩的創(chuàng)意。

          快快嘗試起來,給你的用戶留下第一眼的好印象~

          本文DEMO

          https://github.com/ellisonchan/SplashScreen



          ·················END·················

          推薦閱讀

          ? 耗時(shí)2年,Android進(jìn)階三部曲第三部《Android進(jìn)階指北》出版!

          ? 『BATcoder』做了多年安卓還沒編譯過源碼?一個(gè)視頻帶你玩轉(zhuǎn)!

          ? 『BATcoder』我去!安裝Ubuntu還有坑?

          ? 重生!進(jìn)階三部曲第一部《Android進(jìn)階之光》第2版 出版!

          為了防止失聯(lián),歡迎關(guān)注我的小號(hào)

          ??微信改了推送機(jī)制,真愛請(qǐng)星標(biāo)本公號(hào)??
          瀏覽 107
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  欧美大屌啪啪 | 欧美大屌操逼 | 色色色香蕉 | 成人AC视频| 亚洲一区二区精品 |