├── .gitignore ├── .idea ├── .gitignore ├── compiler.xml ├── dbnavigator.xml ├── deploymentTargetDropDown.xml ├── encodings.xml ├── gradle.xml ├── jarRepositories.xml ├── misc.xml ├── runConfigurations.xml └── vcs.xml ├── LICENSE ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── example │ │ └── splash │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── splash │ │ │ ├── MyApplication.kt │ │ │ ├── activity │ │ │ ├── Android12SplashActivity.kt │ │ │ ├── CustomizeSplashActivity.kt │ │ │ ├── ImageMainActivity.kt │ │ │ ├── JetpackSplashActivity.kt │ │ │ ├── MainActivity.kt │ │ │ ├── OldMainActivity.kt │ │ │ └── SplashActivity.kt │ │ │ ├── observer │ │ │ └── MyLifecycleObserver.kt │ │ │ └── viewmodel │ │ │ └── MyViewModel.kt │ └── res │ │ ├── animator-v22 │ │ └── ic_alarm_animation_button.xml │ │ ├── drawable-v24 │ │ ├── ic_launcher_animated_sample.xml │ │ ├── ic_launcher_animated_sample_2.xml │ │ ├── ic_launcher_foreground.xml │ │ ├── ic_launcher_foreground_animated.xml │ │ └── ic_launcher_sample.xml │ │ ├── drawable-xxhdpi │ │ ├── xiaomi_brand.jpg │ │ └── xiaomi_brand_small.jpg │ │ ├── drawable │ │ ├── ic_alarm.xml │ │ ├── ic_alarm_fab.xml │ │ ├── ic_alarm_small.xml │ │ ├── ic_alarm_tab_static.xml │ │ ├── ic_app_bundle_logo.xml │ │ ├── ic_brand_tm_bold.png │ │ ├── ic_brand_tm_bold_black.png │ │ ├── ic_brand_tm_bold_white.png │ │ ├── ic_brand_tm_bold_yellow.png │ │ ├── ic_brand_tm_normal.png │ │ ├── ic_icon_bird.xml │ │ ├── ic_icon_bird_old.xml │ │ ├── ic_icon_movie.xml │ │ ├── ic_icon_movie_adp.xml │ │ ├── ic_icon_movie_adp_animated.xml │ │ ├── ic_icon_movie_adp_latest.xml │ │ ├── ic_icon_movie_adp_latest_animated.xml │ │ ├── ic_icon_movie_animated.xml │ │ ├── ic_icon_movie_mine.xml │ │ ├── ic_icon_movie_mine_animated.xml │ │ ├── ic_im_movie.xml │ │ ├── ic_kotlin_android.xml │ │ ├── ic_kotlin_hero.xml │ │ ├── ic_kotlin_hero_animated.xml │ │ ├── ic_kotlin_hero_new.xml │ │ ├── ic_kotlin_hero_new_animated.xml │ │ ├── ic_kotlin_hero_new_animated_rotate.xml │ │ ├── ic_kotlin_hero_new_animated_slide.xml │ │ ├── ic_kotlin_hero_new_animated_total.xml │ │ ├── ic_launcher_background.xml │ │ ├── ic_launcher_round_for_splash.png │ │ ├── ic_mi_logo.xml │ │ ├── ic_movie_logo_animated.xml │ │ ├── ic_splash.xml │ │ ├── ic_splash_bg.PNG │ │ ├── ic_splash_bg_kt.xml │ │ ├── ic_splash_test.PNG │ │ ├── ic_splash_xiaomi.xml │ │ ├── ic_splash_zhihu.xml │ │ ├── ic_tm_brand.png │ │ ├── ic_tm_brand_new.png │ │ ├── ic_tm_brand_newer.png │ │ ├── ic_tm_logo.png │ │ ├── ic_vinyl_dark_grey.xml │ │ ├── ic_zhihu_brand.png │ │ ├── ic_zhihu_logo.jpg │ │ ├── xiaomi_logo_2021.png │ │ ├── xiaomi_logo_black.jpg │ │ ├── xiaomi_logo_brand.jpeg │ │ ├── xiaomi_logo_new.jpg │ │ ├── xiaomi_logo_white.jpg │ │ └── xiaomi_logo_white_2.jpg │ │ ├── layout │ │ ├── activity_main.xml │ │ ├── activity_main_simple.xml │ │ ├── activity_splash.xml │ │ ├── activity_splash_cus.xml │ │ └── activity_temp.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_round.png │ │ └── ic_launcher_round_bg.png │ │ ├── values-v23 │ │ ├── styles-new.xml │ │ └── styles.xml │ │ ├── values-v26 │ │ ├── styles-old.xml │ │ └── styles.xml │ │ ├── values-v31 │ │ ├── styles-new.xml │ │ └── styles.xml │ │ └── values │ │ ├── colors.xml │ │ ├── colors_new.xml │ │ ├── constants.xml │ │ ├── strings.xml │ │ ├── styles-new.xml │ │ ├── styles-old.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── example │ └── splash │ └── ExampleUnitTest.kt ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── screenshots ├── jet-splash-enter-12.gif ├── jet-splash-enter-8.gif ├── jet-splash-exit-icon-12.gif ├── jet-splash-exit-icon-8.gif ├── jet-splash-exit-total-12.gif ├── jet-splash-exit-total-8.gif ├── jet-splash-longer-12.gif └── jet-splash-longer-8.gif └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | .cxx 15 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/deploymentTargetDropDown.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 20 | 21 | -------------------------------------------------------------------------------- /.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | 29 | 30 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 32 | 33 | 34 | 35 | 36 | 37 | 39 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Ellison Chan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Jetpack Splash Screen Demo 2 | ![](https://z3.ax1x.com/2021/08/13/fDzSw6.png) 3 | 4 | App demo that used with Jetpack [SplashScreen](https://developer.android.google.cn/jetpack/androidx/releases/core?hl=zh-cn#core_splashscreen_version_100_2) library which helps building app splash page easily. 5 | 6 | * Help to user **Android 12's new Splash Screen API** 7 | * Support to **Android 6** 8 | 9 | ## :camera_flash:Splash screen effect on Android 8 & 12 10 | 11 | ### 1. Enter effect 12 | 13 |
14 | 15 | 16 |
17 | 18 | ### 2. Keep splash effect longer 19 | 20 | 21 |
22 | 23 | 24 |
25 | 26 | ### 3. Exit effect for icon 27 | 28 | 29 | 30 |
31 | 32 | 33 |
34 | 35 | ### 4. Exit effect for total view 36 | 37 | 38 | 39 |
40 | 41 | 42 |
43 | 44 | ## :orange_book: Splash Screen API 45 | 46 | ![](https://z3.ax1x.com/2021/10/01/4ToJ2j.png) 47 | 48 | 49 | ## :orange_book: Reference site 50 | * [Jetpack SplashScreen library ](https://developer.android.google.cn/jetpack/androidx/releases/core?hl=zh-cn#core_splashscreen_version_100_2) 51 | * [Android 12 New Splash Screen API](https://developer.android.google.cn/about/versions/12/features/splash-screen) 52 | ## :orange_book: Blog detail 53 | 54 | * [Jetpack新成员SplashScreen:打造全新的App启动画面](https://juejin.cn/post/6997217571208445965) 55 | 56 | * [Android 12上全新的应用启动画面,适配一下?](https://juejin.cn/post/6962706834889113614) 57 | 58 | ## :copyright: License 59 | ``` 60 | MIT License 61 | 62 | Copyright (c) 2021 Ellison Chan 63 | 64 | Permission is hereby granted, free of charge, to any person obtaining a copy 65 | of this software and associated documentation files (the "Software"), to deal 66 | in the Software without restriction, including without limitation the rights 67 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 68 | copies of the Software, and to permit persons to whom the Software is 69 | furnished to do so, subject to the following conditions: 70 | 71 | The above copyright notice and this permission notice shall be included in all 72 | copies or substantial portions of the Software. 73 | 74 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 75 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 76 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 77 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 78 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 79 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 80 | SOFTWARE. 81 | ``` 82 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'kotlin-android' 3 | apply plugin: 'kotlin-android-extensions' 4 | 5 | android { 6 | // compileSdkVersion 30 7 | compileSdkVersion "android-S" 8 | // compileSdkVersion 30 9 | buildToolsVersion "30.0.2" 10 | 11 | defaultConfig { 12 | applicationId "com.example.splash" 13 | minSdkVersion 24 14 | // targetSdkVersion 30 15 | // targetSdkVersion "S" 16 | targetSdkVersion 31 17 | versionCode 1 18 | versionName "1.0" 19 | 20 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 21 | } 22 | 23 | buildTypes { 24 | release { 25 | minifyEnabled false 26 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 27 | } 28 | } 29 | 30 | viewBinding { 31 | enabled = true 32 | } 33 | 34 | kotlinOptions { 35 | jvmTarget = "1.8" 36 | } 37 | } 38 | 39 | dependencies { 40 | implementation fileTree(dir: "libs", include: ["*.jar"]) 41 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" 42 | implementation 'androidx.appcompat:appcompat:1.1.0' 43 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3' 44 | testImplementation 'junit:junit:4.12' 45 | androidTestImplementation 'androidx.test.ext:junit:1.1.1' 46 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' 47 | 48 | // lifecycle 49 | implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0' 50 | implementation 'androidx.lifecycle:lifecycle-common-java8:2.0.0-rc01' 51 | 52 | // kotlin ktx 53 | implementation 'androidx.core:core-ktx:1.6.0-alpha02' 54 | implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1" 55 | implementation 'androidx.fragment:fragment-ktx:1.2.2' 56 | 57 | // Optional - APIs for SplashScreen, including compatibility helpers on devices prior Android 12 58 | implementation "androidx.core:core-splashscreen:1.0.0-alpha01" 59 | } 60 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /app/src/androidTest/java/com/example/splash/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.example.splash 2 | 3 | import androidx.test.platform.app.InstrumentationRegistry 4 | import androidx.test.ext.junit.runners.AndroidJUnit4 5 | 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | import org.junit.Assert.* 10 | 11 | /** 12 | * Instrumented test, which will execute on an Android device. 13 | * 14 | * See [testing documentation](http://d.android.com/tools/testing). 15 | */ 16 | @RunWith(AndroidJUnit4::class) 17 | class ExampleInstrumentedTest { 18 | @Test 19 | fun useAppContext() { 20 | // Context of the app under test. 21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext 22 | assertEquals("com.example.splash", appContext.packageName) 23 | } 24 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 13 | 14 | 15 | 17 | 18 | 28 | 29 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/splash/MyApplication.kt: -------------------------------------------------------------------------------- 1 | package com.example.splash 2 | 3 | import android.app.Activity 4 | import android.app.Application 5 | import android.os.Bundle 6 | import android.util.Log 7 | 8 | class MyApplication: Application() { 9 | override fun onCreate() { 10 | super.onCreate() 11 | } 12 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/splash/activity/Android12SplashActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.splash.activity 2 | 3 | import android.animation.AnimatorSet 4 | import android.animation.ObjectAnimator 5 | import android.content.Intent 6 | import androidx.appcompat.app.AppCompatActivity 7 | import android.graphics.Path 8 | import android.os.* 9 | import android.util.Log 10 | import android.view.View 11 | import android.view.ViewTreeObserver 12 | import android.view.animation.AnticipateInterpolator 13 | import android.window.SplashScreenView 14 | import androidx.activity.viewModels 15 | import androidx.annotation.RequiresApi 16 | import androidx.core.animation.doOnEnd 17 | import androidx.core.os.BuildCompat 18 | import com.example.splash.R 19 | import com.example.splash.databinding.ActivitySplashBinding 20 | import com.example.splash.observer.MyLifecycleObserver 21 | import com.example.splash.viewmodel.MyViewModel 22 | import java.time.Instant 23 | 24 | class Android12SplashActivity : AppCompatActivity() { 25 | private val handler = Handler(Looper.getMainLooper()) 26 | private val viewModel: MyViewModel by viewModels() 27 | private val jumpRunnable = { goToMainScreen() } 28 | // { 29 | // Log.d("Splash", "goToMainScreen delayed") 30 | // goToMainScreen() 31 | // } 32 | 33 | @RequiresApi(31) 34 | override fun onCreate(savedInstanceState: Bundle?) { 35 | super.onCreate(savedInstanceState) 36 | 37 | val binding = ActivitySplashBinding.inflate(layoutInflater) 38 | setContentView(binding.root) 39 | 40 | MyLifecycleObserver(lifecycle, this).also { lifecycle.addObserver(it) } 41 | 42 | // keepSplashScreenLonger() 43 | 44 | customizeSplashScreenExit() 45 | } 46 | 47 | // Ensure main screen not shown when tap home key during message queueing. 48 | override fun onPause() { 49 | super.onPause() 50 | handler.removeCallbacksAndMessages(null) 51 | } 52 | 53 | // Ensure main screen jump logic can do again. 54 | override fun onResume() { 55 | super.onResume() 56 | goToMainScreenDelayed() 57 | } 58 | 59 | fun onSkipTap(view: View) { 60 | // handler.removeCallbacks(jumpRunnable) 61 | handler.removeCallbacksAndMessages(null) 62 | goToMainScreen() 63 | } 64 | 65 | private fun goToMainScreenDelayed() { 66 | // handler.postDelayed(jumpRunnable, 3000) 67 | handler.postDelayed(jumpRunnable, 3000) 68 | } 69 | 70 | private fun goToMainScreen() { 71 | Intent( 72 | this, 73 | ImageMainActivity::class.java 74 | ).also { startActivity(it) } 75 | finish() 76 | } 77 | 78 | /* 79 | Keep splash screen showing till data initialized. 80 | */ 81 | private fun keepSplashScreenLonger() { 82 | Log.d("Splash", "SplashActivity#keepSplashScreenLonger()") 83 | // 监听Content View的描画时机 84 | val content: View = findViewById(android.R.id.content) 85 | content.viewTreeObserver.addOnPreDrawListener( 86 | object : ViewTreeObserver.OnPreDrawListener { 87 | override fun onPreDraw(): Boolean { 88 | Log.d("Splash", "SplashActivity#onPreDraw() currentTime:${SystemClock.uptimeMillis()}") 89 | // 准备好了描画放行,反之挂起 90 | return if (viewModel.isDataReady()) { 91 | Log.d("Splash", "SplashActivity#onPreDraw() proceed") 92 | content.viewTreeObserver.removeOnPreDrawListener(this) 93 | true 94 | } else { 95 | Log.d("Splash", "SplashActivity#onPreDraw() suspend") 96 | false 97 | } 98 | } 99 | } 100 | ) 101 | } 102 | 103 | /* 104 | Customize splash screen exit animator. 105 | */ 106 | @RequiresApi(31) 107 | private fun customizeSplashScreenExit() { 108 | // Ensure working on S device or above . 109 | if (!BuildCompat.isAtLeastS()) { 110 | return 111 | } 112 | 113 | splashScreen.setOnExitAnimationListener { splashScreenView -> 114 | Log.d( 115 | "Splash", "SplashScreen#onSplashScreenExit view:$splashScreenView" 116 | + " icon:${splashScreenView.iconView}" 117 | + " bg:${splashScreenView.background}" 118 | ) 119 | 120 | // Exit immediately 121 | // Log.d("Splash", "SplashScreen#remove directly") 122 | // splashScreenView.remove() 123 | 124 | // Standard exit animator 125 | // sleep(1000) 126 | // Log.d("Splash", "SplashScreen#remove after sleeping") 127 | // splashScreenView.remove() 128 | 129 | // Customize exit animator 130 | // showSplashExitAnimator(splashScreenView) 131 | showSplashIconExitAnimator(splashScreenView) 132 | } 133 | } 134 | 135 | /* 136 | Show exit animator for splash screen view. 137 | */ 138 | @RequiresApi(31) 139 | private fun showSplashExitAnimator(splashScreenView: SplashScreenView) { 140 | // Single slide up animator. 141 | // val slideUp = ObjectAnimator.ofFloat( 142 | // splashScreenView, 143 | // View.TRANSLATION_Y, 144 | // 0f, 145 | // -splashScreenView.height.toFloat() 146 | // ) 147 | // slideUp.interpolator = AnticipateInterpolator() 148 | // slideUp.duration = 1000L 149 | // // Call SplashScreenView.remove at the end of your custom animation. 150 | // slideUp.doOnEnd { 151 | // Log.d("Splash", "SplashScreen#onSplashScreenExit onEnd remove") 152 | // splashScreenView.remove() 153 | // } 154 | // // Run your animation. 155 | // slideUp.start() 156 | 157 | // Create your custom animation set. 158 | val slideUp = ObjectAnimator.ofFloat( 159 | splashScreenView, 160 | View.TRANSLATION_Y, 161 | 0f, 162 | -splashScreenView.height.toFloat() 163 | ) 164 | val slideLeft = ObjectAnimator.ofFloat( 165 | splashScreenView, 166 | View.TRANSLATION_X, 167 | 0f, 168 | -splashScreenView.width.toFloat() 169 | ) 170 | 171 | val scaleXOut = ObjectAnimator.ofFloat( 172 | splashScreenView, 173 | View.SCALE_X, 174 | 1.0f, 175 | 0f 176 | ) 177 | 178 | val path = Path() 179 | path.moveTo(1.0f, 1.0f) 180 | path.lineTo(0f, 0f) 181 | val scaleOut = ObjectAnimator.ofFloat( 182 | splashScreenView, 183 | View.SCALE_X, 184 | View.SCALE_Y, 185 | path 186 | ) 187 | 188 | val alphaOut = ObjectAnimator.ofFloat( 189 | splashScreenView, 190 | View.ALPHA, 191 | 1f, 192 | 0f 193 | ) 194 | 195 | val animatorSet = AnimatorSet() 196 | animatorSet.duration = resources.getInteger(R.integer.splash_exit_total_duration).toLong() 197 | animatorSet.interpolator = AnticipateInterpolator() 198 | 199 | animatorSet.playTogether(scaleOut) 200 | // animatorSet.playTogether(slideUp) 201 | // animatorSet.playTogether(slideUp, scaleXOut) 202 | // animatorSet.playTogether(slideUp, scaleOut) 203 | // animatorSet.playTogether(slideUp, slideLeft) 204 | // animatorSet.playTogether(slideUp, slideLeft, scaleOut) 205 | // animatorSet.playTogether(slideUp, slideLeft, scaleOut, alphaOut) 206 | 207 | animatorSet.doOnEnd { 208 | Log.d("Splash", "SplashScreen#remove when animator done") 209 | // splashScreenView.setBackgroundColor(android.graphics.Color.BLUE) 210 | splashScreenView.remove() 211 | } 212 | animatorSet.start() 213 | } 214 | 215 | /* 216 | Show exit animator for splash icon. 217 | */ 218 | @RequiresApi(31) 219 | private fun showSplashIconExitAnimator(splashScreenView: SplashScreenView) { 220 | val iconView = splashScreenView.iconView ?: return 221 | 222 | val slideUp = ObjectAnimator.ofFloat( 223 | splashScreenView.iconView, 224 | View.TRANSLATION_Y, 225 | 0f, 226 | -iconView.height * 2.toFloat() 227 | // -iconView.height.toFloat() 228 | ) 229 | slideUp.interpolator = AnticipateInterpolator() 230 | slideUp.duration = resources.getInteger(R.integer.splash_exit_icon_duration).toLong() 231 | // slideUp.duration = getRemainingDuration(splashScreenView) 232 | // getRemainingDuration(splashScreenView) 233 | Log.d("Splash", "SplashScreen#showSplashIconExitAnimator() duration:${slideUp.duration}") 234 | 235 | slideUp.doOnEnd { 236 | Log.d("Splash", "SplashScreen#showSplashIconExitAnimator() onEnd remove") 237 | splashScreenView.remove() 238 | } 239 | slideUp.start() 240 | } 241 | 242 | /* 243 | Calculate remaining duration for splash screen exit animator. 244 | */ 245 | @RequiresApi(31) 246 | private fun getRemainingDuration(splashScreenView: SplashScreenView): Long { 247 | // Get the duration of the animated vector drawable. 248 | // val animationDuration = splashScreenView.iconAnimationDurationMillis 249 | val animationDuration = splashScreenView.iconAnimationDuration?.toMillis() 250 | 251 | // Get the start time of the animation. 252 | // val animationStart = splashScreenView.iconAnimationStartMillis 253 | val animationStart = splashScreenView.iconAnimationStart?.toEpochMilli() 254 | 255 | Log.d( 256 | "Splash", "SplashScreen#getRemainingDuration() animationDuration:$animationDuration" + 257 | " animationStart:$animationStart" + 258 | // " animationStart:${Instant.ofEpochMilli(animationStart).toEpochMilli()}" + 259 | " current:${Instant.ofEpochMilli(System.currentTimeMillis()).toEpochMilli()}" + 260 | " current:${Instant.now().toEpochMilli()}" + 261 | " current:${SystemClock.uptimeMillis()}" 262 | ) 263 | 264 | // Calculate the remaining duration of the animation. 265 | return if (animationDuration != null && animationStart != null) { 266 | (animationDuration - SystemClock.uptimeMillis() + animationStart) 267 | .coerceAtLeast(0L) 268 | } else { 269 | 0L 270 | } 271 | 272 | // // Calculate the remaining duration of the animation. 273 | // var remainingDuration = if (animationDuration != null && animationStart != null) { 274 | // // (animationDuration - Duration.between(animationStart, Instant.now())) 275 | // // (animationDuration - ChronoUnit.MICROS.between(Instant.ofEpochMilli(animationStart * 1000), Instant.now())) 276 | // (animationDuration - SystemClock.uptimeMillis() + animationStart) 277 | // // .coerceAtLeast(0L) 278 | // } else { 279 | // 0L 280 | // } 281 | // 282 | // Log.d("Splash", "SplashScreen#getRemainingDuration() remainingDuration:$remainingDuration") 283 | // remainingDuration = remainingDuration.coerceAtLeast(0L) 284 | // 285 | // Log.d("Splash", "SplashScreen#getRemainingDuration() 2 remainingDuration:$remainingDuration") 286 | // return remainingDuration 287 | } 288 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/splash/activity/CustomizeSplashActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.splash.activity 2 | 3 | import android.content.Intent 4 | import android.graphics.* 5 | import android.graphics.drawable.Animatable 6 | import androidx.appcompat.app.AppCompatActivity 7 | import android.os.Bundle 8 | import android.os.Handler 9 | import android.os.Looper 10 | import android.util.Log 11 | import android.view.View 12 | import android.view.Window 13 | import android.view.WindowManager 14 | import androidx.activity.viewModels 15 | import androidx.annotation.RequiresApi 16 | import androidx.appcompat.app.AlertDialog 17 | import androidx.core.os.BuildCompat 18 | import com.example.splash.databinding.ActivityMainBinding 19 | import com.example.splash.databinding.ActivitySplashCusBinding 20 | import com.example.splash.observer.MyLifecycleObserver 21 | import com.example.splash.viewmodel.MyViewModel 22 | 23 | class CustomizeSplashActivity : AppCompatActivity() { 24 | private val handler = Handler(Looper.getMainLooper()) 25 | 26 | override fun onCreate(savedInstanceState: Bundle?) { 27 | super.onCreate(savedInstanceState) 28 | 29 | val binding = ActivitySplashCusBinding.inflate(layoutInflater) 30 | setContentView(binding.root) 31 | 32 | goToMainScreenDelayed() 33 | } 34 | 35 | private fun goToMainScreenDelayed() { 36 | handler.postDelayed({ goToMainScreen() }, 1000) 37 | } 38 | 39 | private fun goToMainScreen() { 40 | Intent( 41 | this, 42 | OldMainActivity::class.java 43 | ).also { 44 | startActivity(it) 45 | finish() 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/splash/activity/ImageMainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.splash.activity 2 | 3 | import android.graphics.* 4 | import android.graphics.drawable.Animatable 5 | import androidx.appcompat.app.AppCompatActivity 6 | import android.os.Bundle 7 | import android.util.Log 8 | import android.view.View 9 | import android.view.Window 10 | import android.view.WindowManager 11 | import androidx.annotation.RequiresApi 12 | import androidx.appcompat.app.AlertDialog 13 | import androidx.core.os.BuildCompat 14 | import com.example.splash.databinding.ActivityMainBinding 15 | import com.example.splash.observer.MyLifecycleObserver 16 | 17 | class ImageMainActivity : AppCompatActivity() { 18 | @RequiresApi(31) 19 | override fun onCreate(savedInstanceState: Bundle?) { 20 | super.onCreate(savedInstanceState) 21 | MyLifecycleObserver(lifecycle, this).also { lifecycle.addObserver(it) } 22 | 23 | val binding = ActivityMainBinding.inflate(layoutInflater) 24 | setContentView(binding.root) 25 | 26 | playKotlinAnimation(binding) 27 | 28 | // Todo show blur effect. 29 | // showViewRenderEffect(binding.iv) 30 | // listenBlurStatus() 31 | // showDialog() 32 | } 33 | 34 | private fun playKotlinAnimation(binding: ActivityMainBinding) { 35 | val animatable: Animatable = binding.iv.drawable as Animatable 36 | animatable.start() 37 | } 38 | 39 | @RequiresApi(31) 40 | private fun showViewRenderEffect(view: View) { 41 | // Ensure working on S device or above . 42 | if (!BuildCompat.isAtLeastS()) { 43 | return 44 | } 45 | 46 | val radiusX = 13f 47 | val radiusY = 14f 48 | 49 | // view.setRenderEffect(RenderEffect.createBlurEffect(radiusX, radiusY, Shader.TileMode.CLAMP)) 50 | // view.setRenderEffect(RenderEffect.createBlurEffect(radiusX, radiusY, Shader.TileMode.DECAL)) 51 | // view.setRenderEffect(RenderEffect.createBlurEffect(radiusX, radiusY, Shader.TileMode.MIRROR)) 52 | // view.setRenderEffect(RenderEffect.createBlurEffect(radiusX, radiusY, Shader.TileMode.REPEAT)) 53 | // view.setRenderEffect(RenderEffect.createColorFilterEffect(PorterDuffColorFilter(Color.LTGRAY, PorterDuff.Mode.ADD))) 54 | view.setRenderEffect(RenderEffect.createOffsetEffect(113f, 112f)) 55 | } 56 | 57 | @RequiresApi(31) 58 | private fun listenBlurStatus() { 59 | // Ensure working on S device or above . 60 | if (!BuildCompat.isAtLeastS()) { 61 | return 62 | } 63 | 64 | val windowManager = getSystemService(WindowManager::class.java) 65 | windowManager.addCrossWindowBlurEnabledListener { result -> 66 | Log.d( 67 | "Blur", 68 | "addCrossWindowBlurEnabledListener result:$result" 69 | ) 70 | } 71 | Log.d( 72 | "Blur", 73 | "is blur enabled:${windowManager.isCrossWindowBlurEnabled}" 74 | ) 75 | } 76 | 77 | @RequiresApi(31) 78 | private fun showDialog() { 79 | val dialog = AlertDialog.Builder(this) 80 | .setTitle("Warning") 81 | .setMessage("Check out latest commit please.") 82 | .create() 83 | showWindowRenderEffect(dialog.window) 84 | dialog.show() 85 | } 86 | 87 | @RequiresApi(31) 88 | private fun showWindowRenderEffect(window: Window?) { 89 | // Ensure working on S device or above . 90 | if (!BuildCompat.isAtLeastS()) { 91 | return 92 | } 93 | 94 | Log.d("Blur", "showWindowRenderEffect window:$window") 95 | // Todo 96 | window?.addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND) 97 | window?.setBackgroundBlurRadius(30) 98 | } 99 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/splash/activity/JetpackSplashActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.splash.activity 2 | 3 | import android.animation.AnimatorSet 4 | import android.animation.ObjectAnimator 5 | import android.app.Application 6 | import android.content.Intent 7 | import androidx.appcompat.app.AppCompatActivity 8 | import android.graphics.Path 9 | import android.os.* 10 | import android.util.Log 11 | import android.view.View 12 | import android.view.animation.AnticipateInterpolator 13 | import android.window.SplashScreenView 14 | import androidx.activity.viewModels 15 | import androidx.annotation.RequiresApi 16 | import androidx.core.animation.doOnEnd 17 | import androidx.core.splashscreen.SplashScreen 18 | import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen 19 | import androidx.core.splashscreen.SplashScreenViewProvider 20 | import com.example.splash.R 21 | import com.example.splash.databinding.ActivityMainSimpleBinding 22 | import com.example.splash.databinding.ActivitySplashBinding 23 | import com.example.splash.observer.MyLifecycleObserver 24 | import com.example.splash.viewmodel.MyViewModel 25 | import java.time.Instant 26 | 27 | class JetpackSplashActivity : AppCompatActivity() { 28 | private val viewModel: MyViewModel by viewModels() 29 | private lateinit var splashScreen: SplashScreen 30 | private val defaultExitDuration: Long by lazy { 31 | viewModel.getApplication() 32 | .resources.getInteger(R.integer.splash_exit_total_duration).toLong() 33 | } 34 | 35 | override fun onCreate(savedInstanceState: Bundle?) { 36 | super.onCreate(savedInstanceState) 37 | 38 | // Need to be called before setContentView or other view operation on the root view. 39 | splashScreen = installSplashScreen() 40 | 41 | val binding = ActivityMainSimpleBinding.inflate(layoutInflater) 42 | setContentView(binding.root) 43 | 44 | customizeSplashScreen(splashScreen) 45 | } 46 | 47 | private fun customizeSplashScreen(splashScreen: SplashScreen) { 48 | // keepSplashScreenLonger(splashScreen) 49 | customizeSplashScreenExit(splashScreen) 50 | } 51 | 52 | // Keep splash screen showing till data initialized. 53 | private fun keepSplashScreenLonger(splashScreen: SplashScreen) { 54 | Log.d("Splash", "SplashActivity#keepSplashScreenLonger()") 55 | splashScreen.setKeepVisibleCondition { !viewModel.isDataReady() } 56 | } 57 | 58 | // Customize splash screen exit animator. 59 | private fun customizeSplashScreenExit(splashScreen: SplashScreen) { 60 | splashScreen.setOnExitAnimationListener { splashScreenViewProvider -> 61 | Log.d( 62 | "Splash", "SplashScreen#onSplashScreenExit view:$splashScreenViewProvider" 63 | + " view:${splashScreenViewProvider.view}" 64 | + " icon:${splashScreenViewProvider.iconView}" 65 | ) 66 | 67 | // val onExit = { 68 | // splashScreenViewProvider.remove() 69 | // } 70 | 71 | // defaultExitDuration = getRemainingDuration(splashScreenViewProvider) 72 | 73 | // hookViewLayout(splashScreenViewProvider) 74 | 75 | showSplashExitAnimator(splashScreenViewProvider.view) { 76 | splashScreenViewProvider.remove() 77 | } 78 | 79 | showSplashIconExitAnimator(splashScreenViewProvider.iconView) { 80 | splashScreenViewProvider.remove() 81 | } 82 | } 83 | } 84 | 85 | // Show exit animator for splash screen view. 86 | private fun showSplashExitAnimator(splashScreenView: View, onExit: () -> Unit = {}) { 87 | Log.d("Splash", "showSplashExitAnimator() splashScreenView:$splashScreenView" + 88 | " context:${splashScreenView.context}" + 89 | " parent:${splashScreenView.parent}") 90 | 91 | // Create your custom animation set. 92 | val alphaOut = ObjectAnimator.ofFloat( 93 | splashScreenView, 94 | View.ALPHA, 95 | 1f, 96 | 0f 97 | ) 98 | 99 | // Slide up to center. 100 | val slideUp = ObjectAnimator.ofFloat( 101 | splashScreenView, 102 | View.TRANSLATION_Y, 103 | 0f, 104 | // iconView.translationY, 105 | -(splashScreenView.height).toFloat() 106 | ).apply { 107 | addUpdateListener { 108 | Log.d("Splash", "showSplashIconExitAnimator() translationY:${splashScreenView.translationY}") 109 | } 110 | } 111 | 112 | // Slide down to center. 113 | val slideDown = ObjectAnimator.ofFloat( 114 | splashScreenView, 115 | View.TRANSLATION_Y, 116 | 0f, 117 | // iconView.translationY, 118 | (splashScreenView.height).toFloat() 119 | ).apply { 120 | addUpdateListener { 121 | Log.d("Splash", "showSplashIconExitAnimator() translationY:${splashScreenView.translationY}") 122 | } 123 | } 124 | 125 | val scaleOut = ObjectAnimator.ofFloat( 126 | splashScreenView, 127 | View.SCALE_X, 128 | View.SCALE_Y, 129 | Path().apply { 130 | moveTo(1.0f, 1.0f) 131 | lineTo(0f, 0f) 132 | } 133 | ) 134 | 135 | AnimatorSet().run { 136 | duration = defaultExitDuration 137 | interpolator = AnticipateInterpolator() 138 | Log.d("Splash", "showSplashExitAnimator() duration:$duration") 139 | 140 | // playTogether(alphaOut, slideUp) 141 | // playTogether(scaleOut) 142 | // playTogether(alphaOut) 143 | // playTogether(scaleOut, slideUp, alphaOut) 144 | // playTogether(slideUp, alphaOut) 145 | playTogether(slideDown, alphaOut) 146 | 147 | doOnEnd { 148 | Log.d("Splash", "showSplashExitAnimator() onEnd") 149 | Log.d("Splash", "showSplashExitAnimator() onEnd remove") 150 | onExit() 151 | } 152 | 153 | start() 154 | } 155 | } 156 | 157 | // Show exit animator for splash icon. 158 | private fun showSplashIconExitAnimator(iconView: View, onExit: () -> Unit = {}) { 159 | Log.d("Splash", "showSplashIconExitAnimator()" + 160 | " iconView[:${iconView.width}, ${iconView.height}]" + 161 | " translation[:${iconView.translationX}, ${iconView.translationY}]") 162 | 163 | val alphaOut = ObjectAnimator.ofFloat( 164 | iconView, 165 | View.ALPHA, 166 | 1f, 167 | 0f 168 | ) 169 | 170 | // Bird scale out animator. 171 | val scaleOut = ObjectAnimator.ofFloat( 172 | iconView, 173 | View.SCALE_X, 174 | View.SCALE_Y, 175 | Path().apply { 176 | moveTo(1.0f, 1.0f) 177 | lineTo(0.3f, 0.3f) 178 | } 179 | ) 180 | 181 | // Bird slide up to center. 182 | val slideUp = ObjectAnimator.ofFloat( 183 | iconView, 184 | View.TRANSLATION_Y, 185 | 0f, 186 | // iconView.translationY, 187 | -(iconView.height).toFloat() * 2.25f 188 | ).apply { 189 | addUpdateListener { 190 | Log.d("Splash", "showSplashIconExitAnimator() translationY:${iconView.translationY}") 191 | } 192 | } 193 | 194 | AnimatorSet().run { 195 | interpolator = AnticipateInterpolator() 196 | duration = defaultExitDuration 197 | Log.d("Splash", "showSplashIconExitAnimator() duration:$duration") 198 | 199 | // playTogether(alphaOut, slideUp) 200 | playTogether(alphaOut, scaleOut, slideUp) 201 | // playTogether(scaleOut, slideUp) 202 | // playTogether(slideUp) 203 | 204 | doOnEnd { 205 | Log.d("Splash", "showSplashIconExitAnimator() onEnd remove") 206 | onExit() 207 | } 208 | 209 | start() 210 | } 211 | } 212 | 213 | private fun hookViewLayout(splashScreenViewProvider: SplashScreenViewProvider) { 214 | Log.d("Splash", "hookViewLayout()") 215 | val rootWindowInsets = splashScreenViewProvider.view.rootWindowInsets 216 | 217 | Log.d("Splash", "hookViewLayout() rootWindowInsets:$rootWindowInsets" + 218 | // "\n systemWindowInsets:${rootWindowInsets.systemWindowInsets}" + 219 | " top:${rootWindowInsets.systemWindowInsetTop}" + 220 | " bottom${rootWindowInsets.systemWindowInsetBottom}" + 221 | " icon translationY:${splashScreenViewProvider.iconView.translationY}") 222 | } 223 | 224 | private fun getRemainingDuration(splashScreenView: SplashScreenViewProvider): Long { 225 | // Get the duration of the animated vector drawable. 226 | val animationDuration = splashScreenView.iconAnimationDurationMillis 227 | 228 | // Get the start time of the animation. 229 | val animationStart = splashScreenView.iconAnimationStartMillis 230 | 231 | // Calculate the remaining duration of the animation. 232 | return if (animationDuration == 0L || animationStart == 0L) 233 | defaultExitDuration 234 | else (animationDuration - SystemClock.uptimeMillis() + animationStart) 235 | .coerceAtLeast(0L) 236 | } 237 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/splash/activity/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.splash.activity 2 | 3 | import android.graphics.* 4 | import android.graphics.drawable.Animatable 5 | import androidx.appcompat.app.AppCompatActivity 6 | import android.os.Bundle 7 | import android.util.Log 8 | import android.view.View 9 | import android.view.Window 10 | import android.view.WindowManager 11 | import androidx.annotation.RequiresApi 12 | import androidx.appcompat.app.AlertDialog 13 | import androidx.core.os.BuildCompat 14 | import com.example.splash.databinding.ActivityMainBinding 15 | import com.example.splash.observer.MyLifecycleObserver 16 | 17 | class MainActivity : AppCompatActivity() { 18 | @RequiresApi(31) 19 | override fun onCreate(savedInstanceState: Bundle?) { 20 | super.onCreate(savedInstanceState) 21 | MyLifecycleObserver(lifecycle, this).also { lifecycle.addObserver(it) } 22 | 23 | val binding = ActivityMainBinding.inflate(layoutInflater) 24 | setContentView(binding.root) 25 | 26 | playKotlinAnimation(binding) 27 | 28 | // Todo show blur effect. 29 | // showViewRenderEffect(binding.iv) 30 | // listenBlurStatus() 31 | // showDialog() 32 | } 33 | 34 | private fun playKotlinAnimation(binding: ActivityMainBinding) { 35 | val animatable: Animatable = binding.iv.drawable as Animatable 36 | animatable.start() 37 | } 38 | 39 | @RequiresApi(31) 40 | private fun showViewRenderEffect(view: View) { 41 | // Ensure working on S device or above . 42 | if (!BuildCompat.isAtLeastS()) { 43 | return 44 | } 45 | 46 | val radiusX = 13f 47 | val radiusY = 14f 48 | 49 | // view.setRenderEffect(RenderEffect.createBlurEffect(radiusX, radiusY, Shader.TileMode.CLAMP)) 50 | // view.setRenderEffect(RenderEffect.createBlurEffect(radiusX, radiusY, Shader.TileMode.DECAL)) 51 | // view.setRenderEffect(RenderEffect.createBlurEffect(radiusX, radiusY, Shader.TileMode.MIRROR)) 52 | // view.setRenderEffect(RenderEffect.createBlurEffect(radiusX, radiusY, Shader.TileMode.REPEAT)) 53 | // view.setRenderEffect(RenderEffect.createColorFilterEffect(PorterDuffColorFilter(Color.LTGRAY, PorterDuff.Mode.ADD))) 54 | view.setRenderEffect(RenderEffect.createOffsetEffect(113f, 112f)) 55 | } 56 | 57 | @RequiresApi(31) 58 | private fun listenBlurStatus() { 59 | // Ensure working on S device or above . 60 | if (!BuildCompat.isAtLeastS()) { 61 | return 62 | } 63 | 64 | val windowManager = getSystemService(WindowManager::class.java) 65 | windowManager.addCrossWindowBlurEnabledListener { result -> 66 | Log.d( 67 | "Blur", 68 | "addCrossWindowBlurEnabledListener result:$result" 69 | ) 70 | } 71 | Log.d( 72 | "Blur", 73 | "is blur enabled:${windowManager.isCrossWindowBlurEnabled}" 74 | ) 75 | } 76 | 77 | @RequiresApi(31) 78 | private fun showDialog() { 79 | val dialog = AlertDialog.Builder(this) 80 | .setTitle("Warning") 81 | .setMessage("Check out latest commit please.") 82 | .create() 83 | showWindowRenderEffect(dialog.window) 84 | dialog.show() 85 | } 86 | 87 | @RequiresApi(31) 88 | private fun showWindowRenderEffect(window: Window?) { 89 | // Ensure working on S device or above . 90 | if (!BuildCompat.isAtLeastS()) { 91 | return 92 | } 93 | 94 | Log.d("Blur", "showWindowRenderEffect window:$window") 95 | // Todo 96 | window?.addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND) 97 | window?.setBackgroundBlurRadius(30) 98 | } 99 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/splash/activity/OldMainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.splash.activity 2 | 3 | import android.graphics.* 4 | import android.graphics.drawable.Animatable 5 | import androidx.appcompat.app.AppCompatActivity 6 | import android.os.Bundle 7 | import android.os.SystemClock 8 | import android.util.Log 9 | import android.view.View 10 | import android.view.ViewTreeObserver 11 | import android.view.Window 12 | import android.view.WindowManager 13 | import androidx.activity.viewModels 14 | import androidx.annotation.RequiresApi 15 | import androidx.appcompat.app.AlertDialog 16 | import androidx.core.os.BuildCompat 17 | import com.example.splash.databinding.ActivityMainBinding 18 | import com.example.splash.databinding.ActivityMainSimpleBinding 19 | import com.example.splash.observer.MyLifecycleObserver 20 | import com.example.splash.viewmodel.MyViewModel 21 | 22 | class OldMainActivity : AppCompatActivity() { 23 | private val viewModel: MyViewModel by viewModels() 24 | 25 | override fun onCreate(savedInstanceState: Bundle?) { 26 | super.onCreate(savedInstanceState) 27 | val binding = ActivityMainSimpleBinding.inflate(layoutInflater) 28 | setContentView(binding.root) 29 | 30 | // Test for hard work to keep splash screen longer. 31 | // doSomeHardWork() 32 | } 33 | 34 | private fun doSomeHardWork() { 35 | Log.d("Splash", "SplashActivity#doSomeHardWork()") 36 | val content: View = findViewById(android.R.id.content) 37 | 38 | content.viewTreeObserver.addOnPreDrawListener( 39 | object : ViewTreeObserver.OnPreDrawListener { 40 | override fun onPreDraw(): Boolean { 41 | Log.d("Splash", "SplashActivity#onPreDraw() currentTime:${SystemClock.uptimeMillis()}") 42 | 43 | return if (viewModel.isDataReady()) { 44 | Log.d("Splash", "SplashActivity#onPreDraw() proceed") 45 | content.viewTreeObserver.removeOnPreDrawListener(this) 46 | true 47 | } else { 48 | Log.d("Splash", "SplashActivity#onPreDraw() suspend") 49 | false 50 | } 51 | } 52 | } 53 | ) 54 | } 55 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/splash/activity/SplashActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.splash.activity 2 | 3 | import android.animation.AnimatorSet 4 | import android.animation.ObjectAnimator 5 | import android.content.Intent 6 | import androidx.appcompat.app.AppCompatActivity 7 | import android.graphics.Path 8 | import android.graphics.RenderEffect 9 | import android.graphics.Shader 10 | import android.os.* 11 | import android.util.Log 12 | import android.view.View 13 | import android.view.ViewTreeObserver 14 | import android.view.animation.AnticipateInterpolator 15 | import android.window.SplashScreenView 16 | import androidx.activity.viewModels 17 | import androidx.annotation.RequiresApi 18 | import androidx.core.animation.doOnEnd 19 | import androidx.core.os.BuildCompat 20 | import com.example.splash.R 21 | import com.example.splash.databinding.ActivitySplashBinding 22 | import com.example.splash.observer.MyLifecycleObserver 23 | import com.example.splash.viewmodel.MyViewModel 24 | import java.lang.Exception 25 | import java.time.Instant 26 | 27 | class SplashActivity : AppCompatActivity() { 28 | private val handler = Handler(Looper.getMainLooper()) 29 | private val viewModel: MyViewModel by viewModels() 30 | private val jumpRunnable = { goToMainScreen() } 31 | // { 32 | // Log.d("Splash", "goToMainScreen delayed") 33 | // goToMainScreen() 34 | // } 35 | 36 | @RequiresApi(31) 37 | override fun onCreate(savedInstanceState: Bundle?) { 38 | super.onCreate(savedInstanceState) 39 | 40 | val binding = ActivitySplashBinding.inflate(layoutInflater) 41 | setContentView(binding.root) 42 | 43 | MyLifecycleObserver(lifecycle, this).also { lifecycle.addObserver(it) } 44 | 45 | // keepSplashScreenLonger() 46 | customizeSplashScreenExit() 47 | } 48 | 49 | // Ensure main screen not shown when tap home key during message queueing. 50 | override fun onPause() { 51 | super.onPause() 52 | handler.removeCallbacksAndMessages(null) 53 | } 54 | 55 | // Ensure main screen jump logic can do again. 56 | override fun onResume() { 57 | super.onResume() 58 | goToMainScreenDelayed() 59 | } 60 | 61 | fun onSkipTap(view: View) { 62 | // handler.removeCallbacks(jumpRunnable) 63 | handler.removeCallbacksAndMessages(null) 64 | goToMainScreen() 65 | } 66 | 67 | private fun goToMainScreenDelayed() { 68 | // handler.postDelayed(jumpRunnable, 3000) 69 | handler.postDelayed(jumpRunnable, 1500) 70 | } 71 | 72 | private fun goToMainScreen() { 73 | Intent( 74 | this, 75 | MainActivity::class.java 76 | ).also { startActivity(it) } 77 | finish() 78 | } 79 | 80 | /* 81 | Keep splash screen showing till data initialized. 82 | */ 83 | private fun keepSplashScreenLonger() { 84 | Log.d("Splash", "SplashActivity#keepSplashScreenLonger()") 85 | // 监听Content View的描画时机 86 | val content: View = findViewById(android.R.id.content) 87 | content.viewTreeObserver.addOnPreDrawListener( 88 | object : ViewTreeObserver.OnPreDrawListener { 89 | override fun onPreDraw(): Boolean { 90 | Log.d("Splash", "SplashActivity#onPreDraw() currentTime:${SystemClock.uptimeMillis()}") 91 | // 准备好了描画放行,反之挂起 92 | return if (viewModel.isDataReady()) { 93 | Log.d("Splash", "SplashActivity#onPreDraw() proceed") 94 | content.viewTreeObserver.removeOnPreDrawListener(this) 95 | true 96 | } else { 97 | Log.d("Splash", "SplashActivity#onPreDraw() suspend") 98 | false 99 | } 100 | } 101 | } 102 | ) 103 | } 104 | 105 | /* 106 | Customize splash screen exit animator. 107 | */ 108 | @RequiresApi(31) 109 | private fun customizeSplashScreenExit() { 110 | // Ensure working on S device or above . 111 | if (!BuildCompat.isAtLeastS()) { 112 | return 113 | } 114 | 115 | splashScreen.setOnExitAnimationListener { splashScreenView -> 116 | Log.d( 117 | "Splash", "SplashScreen#onSplashScreenExit view:$splashScreenView" 118 | + " icon:${splashScreenView.iconView}" 119 | + " bg:${splashScreenView.background}" 120 | ) 121 | 122 | // Exit immediately 123 | // Log.d("Splash", "SplashScreen#remove directly") 124 | // splashScreenView.remove() 125 | 126 | // Standard exit animator 127 | // sleep(1000) 128 | // Log.d("Splash", "SplashScreen#remove after sleeping") 129 | // splashScreenView.remove() 130 | 131 | // Customize exit animator 132 | // showSplashExitAnimator(splashScreenView) 133 | showSplashIconExitAnimator(splashScreenView) 134 | } 135 | } 136 | 137 | /* 138 | Show exit animator for splash screen view. 139 | */ 140 | @RequiresApi(31) 141 | private fun showSplashExitAnimator(splashScreenView: SplashScreenView) { 142 | // Single slide up animator. 143 | // val slideUp = ObjectAnimator.ofFloat( 144 | // splashScreenView, 145 | // View.TRANSLATION_Y, 146 | // 0f, 147 | // -splashScreenView.height.toFloat() 148 | // ) 149 | // slideUp.interpolator = AnticipateInterpolator() 150 | // slideUp.duration = 1000L 151 | // // Call SplashScreenView.remove at the end of your custom animation. 152 | // slideUp.doOnEnd { 153 | // Log.d("Splash", "SplashScreen#onSplashScreenExit onEnd remove") 154 | // splashScreenView.remove() 155 | // } 156 | // // Run your animation. 157 | // slideUp.start() 158 | 159 | // Create your custom animation set. 160 | val slideUp = ObjectAnimator.ofFloat( 161 | splashScreenView, 162 | View.TRANSLATION_Y, 163 | 0f, 164 | -splashScreenView.height.toFloat() 165 | ) 166 | val slideLeft = ObjectAnimator.ofFloat( 167 | splashScreenView, 168 | View.TRANSLATION_X, 169 | 0f, 170 | -splashScreenView.width.toFloat() 171 | ) 172 | 173 | val scaleXOut = ObjectAnimator.ofFloat( 174 | splashScreenView, 175 | View.SCALE_X, 176 | 1.0f, 177 | 0f 178 | ) 179 | 180 | val path = Path() 181 | path.moveTo(1.0f, 1.0f) 182 | path.lineTo(0f, 0f) 183 | val scaleOut = ObjectAnimator.ofFloat( 184 | splashScreenView, 185 | View.SCALE_X, 186 | View.SCALE_Y, 187 | path 188 | ) 189 | 190 | val alphaOut = ObjectAnimator.ofFloat( 191 | splashScreenView, 192 | View.ALPHA, 193 | 1f, 194 | 0f 195 | ) 196 | 197 | val animatorSet = AnimatorSet() 198 | animatorSet.duration = resources.getInteger(R.integer.splash_exit_total_duration).toLong() 199 | animatorSet.interpolator = AnticipateInterpolator() 200 | 201 | animatorSet.playTogether(scaleOut) 202 | // animatorSet.playTogether(slideUp) 203 | // animatorSet.playTogether(slideUp, scaleXOut) 204 | // animatorSet.playTogether(slideUp, scaleOut) 205 | // animatorSet.playTogether(slideUp, slideLeft) 206 | // animatorSet.playTogether(slideUp, slideLeft, scaleOut) 207 | // animatorSet.playTogether(slideUp, slideLeft, scaleOut, alphaOut) 208 | 209 | animatorSet.doOnEnd { 210 | Log.d("Splash", "SplashScreen#remove when animator done") 211 | // splashScreenView.setBackgroundColor(android.graphics.Color.BLUE) 212 | splashScreenView.remove() 213 | } 214 | animatorSet.start() 215 | } 216 | 217 | /* 218 | Show exit animator for splash icon. 219 | */ 220 | @RequiresApi(31) 221 | private fun showSplashIconExitAnimator(splashScreenView: SplashScreenView) { 222 | val iconView = splashScreenView.iconView ?: return 223 | 224 | val slideUp = ObjectAnimator.ofFloat( 225 | splashScreenView.iconView, 226 | View.TRANSLATION_Y, 227 | 0f, 228 | -iconView.height * 2.toFloat() 229 | // -iconView.height.toFloat() 230 | ) 231 | slideUp.interpolator = AnticipateInterpolator() 232 | slideUp.duration = resources.getInteger(R.integer.splash_exit_icon_duration).toLong() 233 | // slideUp.duration = getRemainingDuration(splashScreenView) 234 | // getRemainingDuration(splashScreenView) 235 | Log.d("Splash", "SplashScreen#showSplashIconExitAnimator() duration:${slideUp.duration}") 236 | 237 | slideUp.doOnEnd { 238 | Log.d("Splash", "SplashScreen#showSplashIconExitAnimator() onEnd remove") 239 | splashScreenView.remove() 240 | } 241 | slideUp.start() 242 | } 243 | 244 | /* 245 | Calculate remaining duration for splash screen exit animator. 246 | */ 247 | @RequiresApi(31) 248 | private fun getRemainingDuration(splashScreenView: SplashScreenView): Long { 249 | // Get the duration of the animated vector drawable. 250 | // val animationDuration = splashScreenView.iconAnimationDurationMillis 251 | val animationDuration = splashScreenView.iconAnimationDuration?.toMillis() 252 | 253 | // Get the start time of the animation. 254 | // val animationStart = splashScreenView.iconAnimationStartMillis 255 | val animationStart = splashScreenView.iconAnimationStart?.toEpochMilli() 256 | 257 | Log.d( 258 | "Splash", "SplashScreen#getRemainingDuration() animationDuration:$animationDuration" + 259 | " animationStart:$animationStart" + 260 | // " animationStart:${Instant.ofEpochMilli(animationStart).toEpochMilli()}" + 261 | " current:${Instant.ofEpochMilli(System.currentTimeMillis()).toEpochMilli()}" + 262 | " current:${Instant.now().toEpochMilli()}" + 263 | " current:${SystemClock.uptimeMillis()}" 264 | ) 265 | 266 | // Calculate the remaining duration of the animation. 267 | return if (animationDuration != null && animationStart != null) { 268 | (animationDuration - SystemClock.uptimeMillis() + animationStart) 269 | .coerceAtLeast(0L) 270 | } else { 271 | 0L 272 | } 273 | 274 | // // Calculate the remaining duration of the animation. 275 | // var remainingDuration = if (animationDuration != null && animationStart != null) { 276 | // // (animationDuration - Duration.between(animationStart, Instant.now())) 277 | // // (animationDuration - ChronoUnit.MICROS.between(Instant.ofEpochMilli(animationStart * 1000), Instant.now())) 278 | // (animationDuration - SystemClock.uptimeMillis() + animationStart) 279 | // // .coerceAtLeast(0L) 280 | // } else { 281 | // 0L 282 | // } 283 | // 284 | // Log.d("Splash", "SplashScreen#getRemainingDuration() remainingDuration:$remainingDuration") 285 | // remainingDuration = remainingDuration.coerceAtLeast(0L) 286 | // 287 | // Log.d("Splash", "SplashScreen#getRemainingDuration() 2 remainingDuration:$remainingDuration") 288 | // return remainingDuration 289 | } 290 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/splash/observer/MyLifecycleObserver.kt: -------------------------------------------------------------------------------- 1 | package com.example.splash.observer 2 | 3 | import android.app.Activity 4 | import android.os.Bundle 5 | import android.util.Log 6 | import androidx.lifecycle.Lifecycle 7 | import androidx.lifecycle.LifecycleObserver 8 | import androidx.lifecycle.OnLifecycleEvent 9 | 10 | class MyLifecycleObserver( 11 | private val lifecycle: Lifecycle, 12 | private val activity: Activity 13 | ) : LifecycleObserver { 14 | @OnLifecycleEvent(Lifecycle.Event.ON_CREATE) 15 | fun onCreate() { 16 | Log.d("Splash", "Activity:$activity Activity:$activity onCreate") 17 | } 18 | 19 | @OnLifecycleEvent(Lifecycle.Event.ON_START) 20 | fun onStart() { 21 | Log.d("Splash", "Activity:$activity onStart") 22 | } 23 | 24 | @OnLifecycleEvent(Lifecycle.Event.ON_RESUME) 25 | fun onResume() { 26 | Log.d("Splash", "Activity:$activity onResume") 27 | } 28 | 29 | @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE) 30 | fun onPause() { 31 | Log.d("Splash", "Activity:$activity onPause") 32 | } 33 | 34 | @OnLifecycleEvent(Lifecycle.Event.ON_STOP) 35 | fun onStop() { 36 | Log.d("Splash", "Activity:$activity onStop") 37 | } 38 | 39 | @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) 40 | fun onDestory() { 41 | Log.d("Splash", "Activity:$activity onDestory") 42 | } 43 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/splash/viewmodel/MyViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.example.splash.viewmodel 2 | 3 | import android.app.Application 4 | import android.os.SystemClock 5 | import androidx.lifecycle.AndroidViewModel 6 | 7 | class MyViewModel(application: Application): AndroidViewModel(application) { 8 | companion object { 9 | const val WORK_DURATION = 2000L 10 | } 11 | private val initTime = SystemClock.uptimeMillis() 12 | fun isDataReady() = SystemClock.uptimeMillis() - initTime > WORK_DURATION 13 | } -------------------------------------------------------------------------------- /app/src/main/res/animator-v22/ic_alarm_animation_button.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 20 | 26 | 32 | 38 | 44 | 50 | 56 | 62 | 68 | 74 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_animated_sample.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 9 | 14 | 18 | 19 | 20 | 21 | 22 | * 23 | 24 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_animated_sample_2.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 10 | 16 | 17 | 18 | 19 | 20 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 15 | 18 | 21 | 22 | 23 | 24 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground_animated.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 10 | 11 | 12 | 18 | 21 | 24 | 25 | 26 | 27 | 32 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_sample.xml: -------------------------------------------------------------------------------- 1 | 6 | 11 | 16 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/xiaomi_brand.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ellisonchan/SplashScreen/5f38c69d482f57de5d47fd7fc43064bb972a633f/app/src/main/res/drawable-xxhdpi/xiaomi_brand.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/xiaomi_brand_small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ellisonchan/SplashScreen/5f38c69d482f57de5d47fd7fc43064bb972a633f/app/src/main/res/drawable-xxhdpi/xiaomi_brand_small.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_alarm.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 23 | 27 | 31 | 35 | 40 | 41 | 45 | 50 | 51 | 52 | 53 | 57 | 61 | 65 | 70 | 71 | 75 | 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_alarm_fab.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 17 | 22 | 25 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_alarm_small.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 17 | 22 | 25 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_alarm_tab_static.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 17 | 23 | 26 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_brand_tm_bold.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ellisonchan/SplashScreen/5f38c69d482f57de5d47fd7fc43064bb972a633f/app/src/main/res/drawable/ic_brand_tm_bold.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_brand_tm_bold_black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ellisonchan/SplashScreen/5f38c69d482f57de5d47fd7fc43064bb972a633f/app/src/main/res/drawable/ic_brand_tm_bold_black.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_brand_tm_bold_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ellisonchan/SplashScreen/5f38c69d482f57de5d47fd7fc43064bb972a633f/app/src/main/res/drawable/ic_brand_tm_bold_white.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_brand_tm_bold_yellow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ellisonchan/SplashScreen/5f38c69d482f57de5d47fd7fc43064bb972a633f/app/src/main/res/drawable/ic_brand_tm_bold_yellow.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_brand_tm_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ellisonchan/SplashScreen/5f38c69d482f57de5d47fd7fc43064bb972a633f/app/src/main/res/drawable/ic_brand_tm_normal.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_icon_movie.xml: -------------------------------------------------------------------------------- 1 | 7 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_icon_movie_adp.xml: -------------------------------------------------------------------------------- 1 | 6 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_icon_movie_adp_animated.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 10 | 15 | 23 | 24 | 25 | 26 | 27 | 28 | * 29 | 30 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_icon_movie_adp_latest.xml: -------------------------------------------------------------------------------- 1 | 6 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_icon_movie_adp_latest_animated.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 10 | 15 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 46 | 53 | 60 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_icon_movie_animated.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 9 | 14 | 18 | 19 | 20 | 21 | 22 | * 23 | 24 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_icon_movie_mine.xml: -------------------------------------------------------------------------------- 1 | 6 | 15 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_icon_movie_mine_animated.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 10 | 19 | 24 | 32 | 33 | 34 | 35 | 36 | 37 | * 38 | 39 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_im_movie.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_kotlin_android.xml: -------------------------------------------------------------------------------- 1 | 7 | 9 | 10 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 27 | 28 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 44 | 45 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 62 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_kotlin_hero.xml: -------------------------------------------------------------------------------- 1 | 7 | 9 | 10 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 27 | 28 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 44 | 45 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 62 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_kotlin_hero_animated.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 10 | 12 | 13 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 30 | 31 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 47 | 48 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 69 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 90 | 91 | 96 | 97 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_kotlin_hero_new.xml: -------------------------------------------------------------------------------- 1 | 7 | 14 | 15 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 37 | 38 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 59 | 60 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 82 | 83 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_kotlin_hero_new_animated_rotate.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 10 | 17 | 18 | 24 | 27 | 30 | 33 | 36 | 39 | 42 | 43 | 44 | 45 | 46 | 54 | 55 | 61 | 64 | 67 | 70 | 73 | 76 | 77 | 78 | 79 | 80 | 87 | 88 | 94 | 97 | 100 | 103 | 106 | 109 | 110 | 111 | 112 | 117 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_kotlin_hero_new_animated_slide.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 10 | 17 | 18 | 24 | 27 | 30 | 33 | 36 | 39 | 42 | 43 | 44 | 45 | 46 | 54 | 55 | 61 | 64 | 67 | 70 | 73 | 76 | 77 | 78 | 79 | 80 | 87 | 88 | 94 | 97 | 100 | 103 | 106 | 109 | 110 | 111 | 112 | 116 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 153 | 154 | 159 | 160 | 165 | 166 | 171 | 172 | 173 | 174 | 175 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_round_for_splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ellisonchan/SplashScreen/5f38c69d482f57de5d47fd7fc43064bb972a633f/app/src/main/res/drawable/ic_launcher_round_for_splash.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_mi_logo.xml: -------------------------------------------------------------------------------- 1 | 6 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_movie_logo_animated.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 9 | 14 | 18 | 19 | 20 | 21 | 22 | * 23 | 24 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_splash.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 17 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_splash_bg.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ellisonchan/SplashScreen/5f38c69d482f57de5d47fd7fc43064bb972a633f/app/src/main/res/drawable/ic_splash_bg.PNG -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_splash_bg_kt.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 11 | 12 | 13 | 14 | 19 | 20 | 26 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_splash_test.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ellisonchan/SplashScreen/5f38c69d482f57de5d47fd7fc43064bb972a633f/app/src/main/res/drawable/ic_splash_test.PNG -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_splash_xiaomi.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 20 | 23 | 24 | 25 | 30 | 32 | 33 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_splash_zhihu.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 11 | 12 | 13 | 14 | 18 | 20 | 21 | 22 | 27 | 29 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_tm_brand.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ellisonchan/SplashScreen/5f38c69d482f57de5d47fd7fc43064bb972a633f/app/src/main/res/drawable/ic_tm_brand.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_tm_brand_new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ellisonchan/SplashScreen/5f38c69d482f57de5d47fd7fc43064bb972a633f/app/src/main/res/drawable/ic_tm_brand_new.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_tm_brand_newer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ellisonchan/SplashScreen/5f38c69d482f57de5d47fd7fc43064bb972a633f/app/src/main/res/drawable/ic_tm_brand_newer.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_tm_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ellisonchan/SplashScreen/5f38c69d482f57de5d47fd7fc43064bb972a633f/app/src/main/res/drawable/ic_tm_logo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_vinyl_dark_grey.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 15 | 22 | 29 | 36 | 43 | 50 | 57 | 58 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_zhihu_brand.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ellisonchan/SplashScreen/5f38c69d482f57de5d47fd7fc43064bb972a633f/app/src/main/res/drawable/ic_zhihu_brand.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_zhihu_logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ellisonchan/SplashScreen/5f38c69d482f57de5d47fd7fc43064bb972a633f/app/src/main/res/drawable/ic_zhihu_logo.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/xiaomi_logo_2021.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ellisonchan/SplashScreen/5f38c69d482f57de5d47fd7fc43064bb972a633f/app/src/main/res/drawable/xiaomi_logo_2021.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/xiaomi_logo_black.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ellisonchan/SplashScreen/5f38c69d482f57de5d47fd7fc43064bb972a633f/app/src/main/res/drawable/xiaomi_logo_black.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/xiaomi_logo_brand.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ellisonchan/SplashScreen/5f38c69d482f57de5d47fd7fc43064bb972a633f/app/src/main/res/drawable/xiaomi_logo_brand.jpeg -------------------------------------------------------------------------------- /app/src/main/res/drawable/xiaomi_logo_new.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ellisonchan/SplashScreen/5f38c69d482f57de5d47fd7fc43064bb972a633f/app/src/main/res/drawable/xiaomi_logo_new.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/xiaomi_logo_white.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ellisonchan/SplashScreen/5f38c69d482f57de5d47fd7fc43064bb972a633f/app/src/main/res/drawable/xiaomi_logo_white.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/xiaomi_logo_white_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ellisonchan/SplashScreen/5f38c69d482f57de5d47fd7fc43064bb972a633f/app/src/main/res/drawable/xiaomi_logo_white_2.jpg -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 20 | 21 | 32 | 33 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main_simple.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_splash.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 |